[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

ojan at chromium.org ojan at chromium.org
Wed Dec 22 12:17:53 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 12aca2558ba019c9cceb7f39eb468a6d5a1c3753
Author: ojan at chromium.org <ojan at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Wed Aug 18 17:34:51 2010 +0000

    2010-08-13  Ojan Vafai  <ojan at chromium.org>
    
            Reviewed by Darin Adler.
    
            add ability to test order-of-magnitude in layout tests
            https://bugs.webkit.org/show_bug.cgi?id=43997
    
            Uses the R^2 value to determine likelihood the performance
            is linear and then logs the x and y axis appropriately to determine
            log n and n^2 cases. These are all estimates though, so we try
            up to three times if we don't get the correct expected result.
    
            In practice, with the tests below, we almost always get the correct
            result, but sometimes the O(1) tests get registered as O(n) or indeterminate.
    
            * perf/array-binary-search-expected.txt: Added.
            * perf/array-binary-search.html: Added.
            * perf/array-nested-loop-expected.txt: Added.
            * perf/array-nested-loop.html: Added.
            * perf/array-push-pop-expected.txt: Added.
            * perf/array-push-pop.html: Added.
            * perf/array-reverse-expected.txt: Added.
            * perf/array-reverse.html: Added.
            * perf/object-keys-expected.txt: Added.
            * perf/object-keys.html: Added.
            * perf/set-attribute-expected.txt: Added.
            * perf/set-attribute.html: Added.
            * perf/typing-at-end-of-line-expected.txt: Added.
            * perf/typing-at-end-of-line.html: Added.
            * resources/magnitude-perf.js: Added.
            (Magnitude.description):
            (Magnitude._log):
            (Magnitude._debug):
            (Magnitude.run):
            (Magnitude._run):
            (Magnitude._rSquared):
            (Magnitude._logIterationInfo):
            (Magnitude._bigOGuess):
            (Magnitude._runIteration):
            (Magnitude):
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@65614 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index c24f99c..03ecf75 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,44 @@
+2010-08-13  Ojan Vafai  <ojan at chromium.org>
+
+        Reviewed by Darin Adler.
+
+        add ability to test order-of-magnitude in layout tests
+        https://bugs.webkit.org/show_bug.cgi?id=43997
+
+        Uses the R^2 value to determine likelihood the performance
+        is linear and then logs the x and y axis appropriately to determine
+        log n and n^2 cases. These are all estimates though, so we try
+        up to three times if we don't get the correct expected result.
+
+        In practice, with the tests below, we almost always get the correct
+        result, but sometimes the O(1) tests get registered as O(n) or indeterminate.
+
+        * perf/array-binary-search-expected.txt: Added.
+        * perf/array-binary-search.html: Added.
+        * perf/array-nested-loop-expected.txt: Added.
+        * perf/array-nested-loop.html: Added.
+        * perf/array-push-pop-expected.txt: Added.
+        * perf/array-push-pop.html: Added.
+        * perf/array-reverse-expected.txt: Added.
+        * perf/array-reverse.html: Added.
+        * perf/object-keys-expected.txt: Added.
+        * perf/object-keys.html: Added.
+        * perf/set-attribute-expected.txt: Added.
+        * perf/set-attribute.html: Added.
+        * perf/typing-at-end-of-line-expected.txt: Added.
+        * perf/typing-at-end-of-line.html: Added.
+        * resources/magnitude-perf.js: Added.
+        (Magnitude.description):
+        (Magnitude._log):
+        (Magnitude._debug):
+        (Magnitude.run):
+        (Magnitude._run):
+        (Magnitude._rSquared):
+        (Magnitude._logIterationInfo):
+        (Magnitude._bigOGuess):
+        (Magnitude._runIteration):
+        (Magnitude):
+
 2010-08-17  Ilya Tikhonovsky  <loislo at chromium.org>
 
         Reviewed by Yury Semikhatsky.
diff --git a/LayoutTests/perf/array-binary-search-expected.txt b/LayoutTests/perf/array-binary-search-expected.txt
new file mode 100644
index 0000000..f53e042
--- /dev/null
+++ b/LayoutTests/perf/array-binary-search-expected.txt
@@ -0,0 +1,3 @@
+Tests that binary search over an array is logarithmic.
+PASS
+
diff --git a/LayoutTests/perf/array-binary-search.html b/LayoutTests/perf/array-binary-search.html
new file mode 100644
index 0000000..33f47f1
--- /dev/null
+++ b/LayoutTests/perf/array-binary-search.html
@@ -0,0 +1,48 @@
+<script src="../resources/magnitude-perf.js"></script>
+<script>
+function setupFunction(magnitude)
+{
+    array = [];
+    for (var i = 0; i < magnitude; i++) {
+        array[i] = i;
+    }
+}
+
+function binarySearch(arry, val) {
+    if (!arry.length)
+        return -1;
+    return help(arry, val, 0, arry.length - 1);
+}
+
+function help(arry, val, start, end) {
+    if (end == start) {
+        if (arry[end] == val)
+            return end;
+        else
+            return -1;
+    }
+
+    var index = start + Math.floor((end - start) / 2);
+    if (arry[index] == val)
+        return index;
+
+    if (arry[index] > val) {
+        if (index == start)
+            return -1;
+        return arguments.callee(arry, val, start, index - 1);
+    }
+
+    if (index == end)
+        return -1;
+
+    return arguments.callee(arry, val, index + 1, end);
+}
+
+function test(magnitude)
+{
+    binarySearch(array, 5);
+}
+
+Magnitude.description("Tests that binary search over an array is logarithmic.");
+Magnitude.run(setupFunction, test, Magnitude.LOGARITHMIC);
+</script>
diff --git a/LayoutTests/perf/array-nested-loop-expected.txt b/LayoutTests/perf/array-nested-loop-expected.txt
new file mode 100644
index 0000000..9a6c313
--- /dev/null
+++ b/LayoutTests/perf/array-nested-loop-expected.txt
@@ -0,0 +1,3 @@
+Tests that doing a nested loop over an array is quadratic.
+PASS
+
diff --git a/LayoutTests/perf/array-nested-loop.html b/LayoutTests/perf/array-nested-loop.html
new file mode 100644
index 0000000..8eb5221
--- /dev/null
+++ b/LayoutTests/perf/array-nested-loop.html
@@ -0,0 +1,22 @@
+<script src="../resources/magnitude-perf.js"></script>
+<script>
+function setupFunction(magnitude)
+{
+    array = [];
+    for (var i = 0; i < magnitude; i++) {
+        array[i] = i;
+    }
+}
+
+function test(magnitude)
+{
+    for (var i = 0; i < array.length; i++) {
+        for (var j = 0; j < array.length; j++) {
+            var foo = array[i] + array[j];
+        }
+    }
+}
+
+Magnitude.description("Tests that doing a nested loop over an array is quadratic.");
+Magnitude.run(setupFunction, test, Magnitude.POLYNOMIAL);
+</script>
diff --git a/LayoutTests/perf/array-push-pop-expected.txt b/LayoutTests/perf/array-push-pop-expected.txt
new file mode 100644
index 0000000..d07d4d8
--- /dev/null
+++ b/LayoutTests/perf/array-push-pop-expected.txt
@@ -0,0 +1,3 @@
+Tests that pushing and popping from an array is constant time.
+PASS
+
diff --git a/LayoutTests/perf/array-push-pop.html b/LayoutTests/perf/array-push-pop.html
new file mode 100644
index 0000000..5c1f34e
--- /dev/null
+++ b/LayoutTests/perf/array-push-pop.html
@@ -0,0 +1,19 @@
+<script src="../resources/magnitude-perf.js"></script>
+<script>
+function setupFunction(magnitude)
+{
+    array = [];
+    for (var i = 0; i < magnitude; i++) {
+        array[i] = i;
+    }
+}
+
+function test(magnitude)
+{
+    array.push(1);
+    array.pop();
+}
+
+Magnitude.description("Tests that pushing and popping from an array is constant time.");
+Magnitude.run(setupFunction, test, Magnitude.CONSTANT);
+</script>
diff --git a/LayoutTests/perf/array-reverse-expected.txt b/LayoutTests/perf/array-reverse-expected.txt
new file mode 100644
index 0000000..029d69d
--- /dev/null
+++ b/LayoutTests/perf/array-reverse-expected.txt
@@ -0,0 +1,3 @@
+Tests that Array reverse is linear.
+PASS
+
diff --git a/LayoutTests/perf/array-reverse.html b/LayoutTests/perf/array-reverse.html
new file mode 100644
index 0000000..a1fc03e
--- /dev/null
+++ b/LayoutTests/perf/array-reverse.html
@@ -0,0 +1,18 @@
+<script src="../resources/magnitude-perf.js"></script>
+<script>
+function setupFunction(magnitude)
+{
+    array = [];
+    for (var i = 0; i < magnitude; i++) {
+        array[i] = i;
+    }
+}
+
+function test(magnitude)
+{
+    array.lastIndexOf(1);
+}
+
+Magnitude.description("Tests that Array reverse is linear.");
+Magnitude.run(setupFunction, test, Magnitude.LINEAR);
+</script>
diff --git a/LayoutTests/perf/object-keys-expected.txt b/LayoutTests/perf/object-keys-expected.txt
new file mode 100644
index 0000000..8f7891f
--- /dev/null
+++ b/LayoutTests/perf/object-keys-expected.txt
@@ -0,0 +1,3 @@
+Tests that Object.keys is linear.
+PASS
+
diff --git a/LayoutTests/perf/object-keys.html b/LayoutTests/perf/object-keys.html
new file mode 100644
index 0000000..7ee8f69
--- /dev/null
+++ b/LayoutTests/perf/object-keys.html
@@ -0,0 +1,18 @@
+<script src="../resources/magnitude-perf.js"></script>
+<script>
+function setupFunction(magnitude)
+{
+    obj = {};
+    for (var i = 0; i < magnitude; i++) {
+        obj[i] = i;
+    }
+}
+
+function test(magnitude)
+{
+    Object.keys(obj);
+}
+
+Magnitude.description("Tests that Object.keys is linear.");
+Magnitude.run(setupFunction, test, Magnitude.LINEAR);
+</script>
diff --git a/LayoutTests/perf/set-attribute-expected.txt b/LayoutTests/perf/set-attribute-expected.txt
new file mode 100644
index 0000000..fb8b0fb
--- /dev/null
+++ b/LayoutTests/perf/set-attribute-expected.txt
@@ -0,0 +1,3 @@
+Tests that setAttribute is constant time.
+PASS
+
diff --git a/LayoutTests/perf/set-attribute.html b/LayoutTests/perf/set-attribute.html
new file mode 100644
index 0000000..534801b
--- /dev/null
+++ b/LayoutTests/perf/set-attribute.html
@@ -0,0 +1,19 @@
+<script src="../resources/magnitude-perf.js"></script>
+<script>
+var key = 'counter';
+
+function setupFunction(magnitude)
+{
+    element = document.createElement('div');
+    counter = 0;
+}
+
+function test(magnitude)
+{
+    element.setAttribute(key, counter ? counter-- : counter++);
+}
+
+Magnitude.description("Tests that setAttribute is constant time.");
+Magnitude.run(setupFunction, test, Magnitude.CONSTANT);
+</script>
+</body>
\ No newline at end of file
diff --git a/LayoutTests/perf/typing-at-end-of-line-expected.txt b/LayoutTests/perf/typing-at-end-of-line-expected.txt
new file mode 100644
index 0000000..54d6f7a
--- /dev/null
+++ b/LayoutTests/perf/typing-at-end-of-line-expected.txt
@@ -0,0 +1,3 @@
+Tests that typing at the end of a line where the line-breaks are all BRs is linear in the number of lines.
+PASS
+
diff --git a/LayoutTests/perf/typing-at-end-of-line.html b/LayoutTests/perf/typing-at-end-of-line.html
new file mode 100644
index 0000000..e5723fa
--- /dev/null
+++ b/LayoutTests/perf/typing-at-end-of-line.html
@@ -0,0 +1,32 @@
+<body>
+<script src="../resources/magnitude-perf.js"></script>
+<script>
+document.designMode = 'on';
+
+function placeSelectionAfterFirstBr()
+{
+    var children = document.body.childNodes;
+    for (var i = 0, len = children.length; i < len; i++) {
+        if (children[i].localName == 'br') {
+            window.getSelection().setBaseAndExtent(document.body, i, document.body, i);
+            return;
+        }
+    }
+}
+
+function setupFunction(magnitude)
+{
+    document.body.innerHTML = new Array(magnitude + 1).join('a<br>');
+    placeSelectionAfterFirstBr();
+}
+
+function test(magnitude)
+{
+    if (window.eventSender)
+        eventSender.keyDown('z');
+}
+
+Magnitude.description("Tests that typing at the end of a line where the line-breaks are all BRs is linear in the number of lines.");
+Magnitude.run(setupFunction, test, Magnitude.LINEAR);
+</script>
+</body>
diff --git a/LayoutTests/resources/magnitude-perf.js b/LayoutTests/resources/magnitude-perf.js
new file mode 100644
index 0000000..a8c7273
--- /dev/null
+++ b/LayoutTests/resources/magnitude-perf.js
@@ -0,0 +1,223 @@
+// Magnitude gives a best guess estimate of the runtime of a function.
+// Magnitude.run can be called multiple times in a single test if desired.
+//
+// Usage:
+// <script src="../resources/magnitude-perf.js"></script>
+// <script>
+// ...
+// Magnitude.run(setup, test, expected)
+// </script>
+//
+// -setup is the function to run once before the test-loop. It takes a magnitude argument
+// that is the value of "n".
+// -test is the code whose runtime is being tests. It also takes a magnitude argument.
+// -expected is one of the run-time constants listed below (e.g. Magnitude.CONSTANT).
+
+if (window.layoutTestController)
+    layoutTestController.dumpAsText();
+
+// Namespace.
+var Magnitude = {};
+
+// The description of what this test is testing. Gets prepended to the dumped markup.
+Magnitude.description = function(description)
+{
+    Magnitude._log(description);
+}
+
+Magnitude._numPoints = 10;
+Magnitude._minIterations = 5;
+Magnitude._maxIterations = 1000;
+
+Magnitude.CONSTANT = "O(1)";
+Magnitude.LINEAR = "O(n)";
+Magnitude.LOGARITHMIC = "O(log n)";
+Magnitude.POLYNOMIAL = ">=O(n^2)";
+Magnitude.INDETERMINATE = "indeterminate result";
+
+Magnitude._log = function(msg)
+{
+    if (!Magnitude._container)
+        Magnitude._container = document.createElement('pre');
+    Magnitude._container.appendChild(document.createTextNode(msg + '\n'));
+}
+
+Magnitude._debug = function(msg)
+{
+    Magnitude._debugLog += msg + '\n';
+}
+
+Magnitude.run = function(setup, test, expected)
+{
+    Magnitude._debugLog = "\nDEBUG LOG:\n";
+
+    Magnitude._magnitudes = [];
+    for (var i = 0; i < Magnitude._numPoints; i++) {
+        Magnitude._magnitudes.push(Math.pow(2, i));
+    }
+
+    var milliseconds = 50;
+    var runsPerIteration = 1;
+    var numTries = 3;
+    Magnitude._run(setup, test, expected, milliseconds, runsPerIteration, numTries);
+}
+
+Magnitude._run = function(setup, test, expected, milliseconds, runsPerIteration, numTriesLeft)
+{
+    Magnitude._iterations = {};
+    var maxMagnitude = Magnitude._magnitudes[Magnitude._magnitudes.length - 1];
+
+    // We want the largest magnitude to do between Magnitude._minIterations and Magnitude._maxIterations iterations.
+    // If it's too fast, we increase the runsPerIteration to do more runs per iteration.
+    // If it's too slow, we increase milliseconds to give each iteration more time.
+    while (true) {
+        var iterations = Magnitude._runIteration(setup, test, maxMagnitude, milliseconds, runsPerIteration);
+        Magnitude._debug("iterations " + iterations);
+
+        // If we get too few or too many on the largest magnitude iterations, then we can't trust this run.
+        // Too many runs means the the test loop itself may be taking more time than running the test.
+        if (iterations <= Magnitude._minIterations)
+            milliseconds = Math.max(2, Math.floor(Magnitude._minIterations / iterations)) * milliseconds;
+        else if (iterations > Magnitude._maxIterations)
+            runsPerIteration = Math.max(2, Math.floor(iterations / Magnitude._maxIterations)) * runsPerIteration;
+        else {
+            Magnitude._iterations[maxMagnitude] = iterations;
+            break;
+        }
+    }
+
+    for (var i = 0; i < Magnitude._magnitudes.length - 1; i++) {
+        var magnitude = Magnitude._magnitudes[i];
+        Magnitude._iterations[magnitude] = Magnitude._runIteration(setup, test, magnitude, milliseconds, runsPerIteration);
+    }
+
+    Magnitude._logIterationInfo(milliseconds, runsPerIteration);
+
+    numTriesLeft--;
+    var bigO = Magnitude._bigOGuess(milliseconds);
+    if (bigO == expected || numTriesLeft < 1) {
+        Magnitude._log(bigO == expected ? "PASS" : "FAIL: got " + bigO + " expected " + expected);
+
+        // By default don't log detailed information to layout test results to keep expected results
+        // consistent from run to run.
+        if (!window.layoutTestController || bigO != expected)
+            Magnitude._log(Magnitude._debugLog);
+    } else {
+        Magnitude._debug("numTriesLeft: " + numTriesLeft);
+        arguments.callee(setup, test, expected, milliseconds, runsPerIteration, numTriesLeft);
+    }
+}
+
+Magnitude._rSquared = function(milliseconds, opt_xTransform, opt_yTransform)
+{
+    // Implement http://www.easycalculation.com/statistics/learn-correlation.php.
+    // x = magnitude
+    // y = iterations
+    var sumX = 0;
+    var sumY = 0;
+    var sumXSquared = 0;
+    var sumYSquared = 0;
+    var sumXTimesY = 0;
+
+    var numPoints = Magnitude._magnitudes.length;
+
+    for (var i = 0; i < numPoints; i++) {
+        var x = Magnitude._magnitudes[i];
+        if (opt_xTransform)
+            x = opt_xTransform(x);
+
+        var y = milliseconds / Magnitude._iterations[Magnitude._magnitudes[i]];
+        if (opt_yTransform)
+            y = opt_yTransform(y);
+
+        sumX += x;
+        sumY += y;
+        sumXSquared += x * x;
+        sumYSquared += y * y;
+        sumXTimesY += x * y;
+    }
+
+    var r = (numPoints * sumXTimesY - sumX * sumY) /
+        Math.sqrt((numPoints * sumXSquared - sumX * sumX) *
+                  (numPoints * sumYSquared - sumY * sumY));
+
+    if (isNaN(r) || r == Math.Infinity)
+        r = 0;
+
+    rSquared = r * r;
+
+    var slope = (numPoints * sumXTimesY - sumX * sumY) /
+        (numPoints * sumXSquared - sumX * sumX);
+    var intercept = sumY / numPoints - slope * sumX / numPoints;
+    Magnitude._debug("numPoints " + numPoints + " slope " + slope + " intercept " + intercept + " rSquared " + rSquared);
+
+    return rSquared;
+}
+
+Magnitude._logIterationInfo = function(milliseconds, runsPerIteration)
+{
+    var iterationsArray = [];
+    for (var i = 0; i < Magnitude._magnitudes.length; i++) {
+        var magnitude = Magnitude._magnitudes[i];
+        var iterations = Magnitude._iterations[magnitude];
+        iterationsArray.push(iterations);
+        Magnitude._debug("magnitude: " + magnitude + " iterations: " + iterations + " runsPerIteration " + runsPerIteration +
+                " loop-time " + milliseconds + " time/iteration(ms): " + milliseconds / iterations);
+    }
+
+    // Print out the magnitudes/arrays in CSV to afford easy copy-paste to a charting application.
+    Magnitude._debug("magnitudes: " + Magnitude._magnitudes.join(','));
+    Magnitude._debug("iterations: " + iterationsArray.join(','));
+    Magnitude._debug("milliseconds/iteration: " + iterationsArray.map(function(iterations) {return milliseconds / iterations}).join(','));
+}
+
+Magnitude._bigOGuess = function(milliseconds)
+{
+    var rSquared = Magnitude._rSquared(milliseconds);
+    var rSquaredXLog = Magnitude._rSquared(milliseconds, Math.log);
+    var rSquaredXYLog = Magnitude._rSquared(milliseconds, Math.log, Math.log);
+    Magnitude._debug("rSquared " + rSquared + " rSquaredXLog " + rSquaredXLog + " rSquaredXYLog " + rSquaredXYLog);
+
+    var rSquaredMax = Math.max(rSquared, rSquaredXLog, rSquaredXYLog);
+
+    var bigO = Magnitude.INDETERMINATE;
+
+    // FIXME: These numbers were chosen arbitrarily.
+    // Are there a better value to check against? Do we need to check rSquaredMax?
+    if (rSquared < 0.8 && rSquaredMax < 0.9)
+        bigO = Magnitude.CONSTANT;
+    else if (rSquaredMax > 0.9) {
+        if (rSquared == rSquaredMax)
+            bigO = Magnitude.LINEAR;
+        else if (rSquaredXLog == rSquaredMax)
+            bigO = Magnitude.LOGARITHMIC;
+        else if (rSquaredXYLog == rSquaredMax)
+            bigO = Magnitude.POLYNOMIAL;
+    }
+
+    return bigO;
+}
+
+Magnitude._runIteration = function(setup, test, magnitude, milliseconds, runsPerIteration)
+{
+    Magnitude._debug('run iteration. magnitude ' + magnitude + " milliseconds " + milliseconds + " runsPerIteration " + runsPerIteration);
+    setup(magnitude);
+
+    var start = Date.now();
+    var iterations = 0;
+    while (Date.now() - start < milliseconds) {
+        // Loop runsPerIteration times to reduce errors due to the overhead and granularity of the Date object.
+        for (var i = 0; i < runsPerIteration; i++) {
+            test(magnitude);
+        }
+        iterations++;
+    }
+    return iterations;
+}
+
+window.addEventListener('load', function() {
+    // FIXME: Add Magnitude.waitUntilDone/notifyDone for tests that need to operate after the load event has fired.
+    if (window.layoutTestController)
+        document.body.innerHTML = '';
+    document.body.appendChild(Magnitude._container);
+}, false);

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list