source: trunk/LayoutTests/resources/magnitude-perf.js @ 185041

Revision 135335, 7.0 KB checked in by rniwa@webkit.org, 3 years ago (diff)

REGRESSION(r131106): magnitude-perf.js calls bind on undefined
https://bugs.webkit.org/show_bug.cgi?id=102848

Reviewed by Tony Gentilcore.

Check the existence of performance.now before calling bind on it.

  • resources/magnitude-perf.js:

(Magnitude._runIteration):

  • Property svn:eol-style set to LF
Line 
1// Magnitude gives a best guess estimate of the runtime of a function.
2// Magnitude.run can be called multiple times in a single test if desired.
3//
4// Usage:
5// <script src="../resources/magnitude-perf.js"></script>
6// <script>
7// ...
8// Magnitude.run(setup, test, expected)
9// </script>
10//
11// -setup is the function to run once before the test-loop. It takes a magnitude argument
12// that is the value of "n".
13// -test is the code whose runtime is being tests. It also takes a magnitude argument.
14// -expected is one of the run-time constants listed below (e.g. Magnitude.CONSTANT).
15
16if (window.testRunner)
17    testRunner.dumpAsText();
18
19// Namespace.
20var Magnitude = {};
21
22// The description of what this test is testing. Gets prepended to the dumped markup.
23Magnitude.description = function(description)
24{
25    Magnitude._log(description);
26}
27
28Magnitude.numPoints = 8;
29Magnitude.millisecondsPerIteration = 25;
30Magnitude.initialMagnitude = 1;
31
32Magnitude.CONSTANT = "O(1)";
33Magnitude.LINEAR = "O(n)";
34Magnitude.LOGARITHMIC = "O(log n)";
35Magnitude.POLYNOMIAL = ">=O(n^2)";
36Magnitude.INDETERMINATE = "indeterminate result";
37
38Magnitude._order = {}
39Magnitude._order[Magnitude.CONSTANT] = 1;
40Magnitude._order[Magnitude.LINEAR] = 2;
41Magnitude._order[Magnitude.LOGARITHMIC] = 3;
42Magnitude._order[Magnitude.POLYNOMIAL] = 4;
43Magnitude._order[Magnitude.INDETERMINATE] = 5;
44
45Magnitude._log = function(msg)
46{
47    if (!Magnitude._container)
48        Magnitude._container = document.createElement('pre');
49    Magnitude._container.appendChild(document.createTextNode(msg + '\n'));
50}
51
52Magnitude._debug = function(msg)
53{
54    Magnitude._debugLog += msg + '\n';
55}
56
57Magnitude.run = function(setup, test, expected)
58{
59    Magnitude._debugLog = "\nDEBUG LOG:\n";
60
61    Magnitude._magnitudes = [];
62    for (var i = Magnitude.initialMagnitude; i < Magnitude.numPoints + Magnitude.initialMagnitude; i++)
63        Magnitude._magnitudes.push(Math.pow(2, i));
64
65    var numTries = 3;
66    Magnitude._run(setup, test, expected, numTries);
67}
68
69Magnitude._run = function(setup, test, expected, numTriesLeft)
70{
71    Magnitude._iterations = {};
72    for (var i = 0; i < Magnitude._magnitudes.length; i++) {
73        var magnitude = Magnitude._magnitudes[i];
74        Magnitude._iterations[magnitude] = Magnitude._runIteration(setup, test, magnitude);
75    }
76
77    Magnitude._logIterationInfo();
78
79    numTriesLeft--;
80    var bigO = Magnitude._bigOGuess();
81    var passed = Magnitude._order[bigO] <= Magnitude._order[expected];
82    if (passed || numTriesLeft < 1) {
83        Magnitude._log(passed ? "PASS" : "FAIL: got " + bigO + " expected " + expected);
84
85        // By default don't log detailed information to layout test results to keep expected results
86        // consistent from run to run.
87        if (!window.testRunner || !passed)
88            Magnitude._log(Magnitude._debugLog);
89    } else {
90        Magnitude._debug("numTriesLeft: " + numTriesLeft);
91        arguments.callee(setup, test, expected, numTriesLeft);
92    }
93}
94
95Magnitude._rSquared = function(opt_xTransform, opt_yTransform)
96{
97    // Implement http://www.easycalculation.com/statistics/learn-correlation.php.
98    // x = magnitude
99    // y = iterations
100    var sumX = 0;
101    var sumY = 0;
102    var sumXSquared = 0;
103    var sumYSquared = 0;
104    var sumXTimesY = 0;
105
106    var numPoints = Magnitude._magnitudes.length;
107
108    for (var i = 0; i < numPoints; i++) {
109        var x = Magnitude._magnitudes[i];
110        if (opt_xTransform)
111            x = opt_xTransform(x);
112
113        var y = Magnitude.millisecondsPerIteration / Magnitude._iterations[Magnitude._magnitudes[i]];
114        if (opt_yTransform)
115            y = opt_yTransform(y);
116
117        sumX += x;
118        sumY += y;
119        sumXSquared += x * x;
120        sumYSquared += y * y;
121        sumXTimesY += x * y;
122    }
123
124    var r = (numPoints * sumXTimesY - sumX * sumY) /
125        Math.sqrt((numPoints * sumXSquared - sumX * sumX) *
126                  (numPoints * sumYSquared - sumY * sumY));
127
128    if (isNaN(r) || r == Math.Infinity)
129        r = 0;
130
131    rSquared = r * r;
132
133    var slope = (numPoints * sumXTimesY - sumX * sumY) /
134        (numPoints * sumXSquared - sumX * sumX);
135    var intercept = sumY / numPoints - slope * sumX / numPoints;
136    Magnitude._debug("numPoints " + numPoints + " slope " + slope + " intercept " + intercept + " rSquared " + rSquared);
137
138    return rSquared;
139}
140
141Magnitude._logIterationInfo = function()
142{
143    var iterationsArray = [];
144    for (var i = 0; i < Magnitude._magnitudes.length; i++) {
145        var magnitude = Magnitude._magnitudes[i];
146        var iterations = Magnitude._iterations[magnitude];
147        iterationsArray.push(iterations);
148    }
149
150    // Print out the magnitudes/arrays in CSV to afford easy copy-paste to a charting application.
151    Magnitude._debug("magnitudes: " + Magnitude._magnitudes.join(','));
152    Magnitude._debug("iterations: " + iterationsArray.join(','));
153}
154
155Magnitude._bigOGuess = function()
156{
157    var rSquared = Magnitude._rSquared();
158    var rSquaredXLog = Magnitude._rSquared(Math.log);
159    var rSquaredXYLog = Magnitude._rSquared(Math.log, Math.log);
160    Magnitude._debug("rSquared " + rSquared + " rSquaredXLog " + rSquaredXLog + " rSquaredXYLog " + rSquaredXYLog);
161
162    var rSquaredMax = Math.max(rSquared, rSquaredXLog, rSquaredXYLog);
163
164    var bigO = Magnitude.INDETERMINATE;
165
166    // FIXME: These numbers were chosen arbitrarily.
167    // Are there a better value to check against? Do we need to check rSquaredMax?
168    if (rSquared < 0.8 && rSquaredMax < 0.9)
169        bigO = Magnitude.CONSTANT;
170    else if (rSquaredMax > 0.9) {
171        if (rSquared == rSquaredMax)
172            bigO = Magnitude.LINEAR;
173        else if (rSquaredXLog == rSquaredMax)
174            bigO = Magnitude.LOGARITHMIC;
175        else if (rSquaredXYLog == rSquaredMax)
176            bigO = Magnitude.POLYNOMIAL;
177    }
178
179    return bigO;
180}
181
182Magnitude._runIteration = function(setup, test, magnitude)
183{
184    setup(magnitude);
185
186    var debugStr = 'run iteration. magnitude ' + magnitude;
187    if (window.GCController) {
188        if (GCController.getJSObjectCount)
189            debugStr += " jsObjectCountBefore " + GCController.getJSObjectCount();
190
191        // Do a gc to reduce likelihood of gc during the test run.
192        // Do multiple gc's for V8 to clear DOM wrappers.
193        GCController.collect();
194        GCController.collect();
195        GCController.collect();
196
197        if (GCController.getJSObjectCount)
198            debugStr += " jsObjectCountAfter " + GCController.getJSObjectCount();
199    }
200
201    Magnitude._debug(debugStr);
202
203    var iterations = 0;
204    var nowFunction = window.performance && window.performance.now ? window.performance.now.bind(window.performance) : Date.now;
205    var start = nowFunction();
206    while (nowFunction() - start < Magnitude.millisecondsPerIteration) {
207        test(magnitude);
208        iterations++;
209    }
210    return iterations;
211}
212
213window.addEventListener('load', function() {
214    // FIXME: Add Magnitude.waitUntilDone/notifyDone for tests that need to operate after the load event has fired.
215    if (window.testRunner)
216        document.body.innerHTML = '';
217    document.body.appendChild(Magnitude._container);
218}, false);
Note: See TracBrowser for help on using the repository browser.