1 // FIXME: Use the real promise if available.
2 // FIXME: Make sure this interface is compatible with the real Promise.
3 function SimplePromise() {
4 this._chainedPromise = null;
8 SimplePromise.prototype.then = function (callback) {
10 throw "SimplePromise doesn't support multiple calls to then";
11 this._callback = callback;
12 this._chainedPromise = new SimplePromise;
15 this.resolve(this._resolvedValue);
17 return this._chainedPromise;
20 SimplePromise.prototype.resolve = function (value) {
21 if (!this._callback) {
22 this._resolved = true;
23 this._resolvedValue = value;
27 var result = this._callback(value);
28 if (result instanceof SimplePromise) {
29 var chainedPromise = this._chainedPromise;
30 result.then(function (result) { chainedPromise.resolve(result); });
32 this._chainedPromise.resolve(result);
35 function BenchmarkTestStep(testName, testFunction) {
37 this.run = testFunction;
40 function BenchmarkRunner(suites, client) {
41 this._suites = suites;
42 this._prepareReturnValue = null;
43 this._client = client;
46 BenchmarkRunner.prototype.waitForElement = function (selector) {
47 var promise = new SimplePromise;
48 var contentDocument = this._frame.contentDocument;
50 function resolveIfReady() {
51 var element = contentDocument.querySelector(selector);
53 return promise.resolve(element);
54 setTimeout(resolveIfReady, 50);
61 BenchmarkRunner.prototype._removeFrame = function () {
63 this._frame.parentNode.removeChild(this._frame);
68 BenchmarkRunner.prototype._appendFrame = function (src) {
69 var frame = document.createElement('iframe');
70 frame.style.width = '800px';
71 frame.style.height = '600px';
72 frame.style.border = '0px none';
73 frame.style.position = 'absolute';
74 frame.setAttribute('scrolling', 'no');
76 var marginLeft = parseInt(getComputedStyle(document.body).marginLeft);
77 var marginTop = parseInt(getComputedStyle(document.body).marginTop);
78 if (window.innerWidth > 800 + marginLeft && window.innerHeight > 600 + marginTop) {
79 frame.style.left = marginLeft + 'px';
80 frame.style.top = marginTop + 'px';
82 frame.style.left = '0px';
83 frame.style.top = '0px';
86 if (this._client && this._client.willAddTestFrame)
87 this._client.willAddTestFrame(frame);
89 document.body.insertBefore(frame, document.body.firstChild);
94 BenchmarkRunner.prototype._waitAndWarmUp = function () {
95 var startTime = Date.now();
97 function Fibonacci(n) {
98 if (Date.now() - startTime > 100)
104 return Fibonacci(n - 2) + Fibonacci(n - 1);
107 var promise = new SimplePromise;
108 setTimeout(function () {
115 // This function ought be as simple as possible. Don't even use SimplePromise.
116 BenchmarkRunner.prototype._runTest = function(suite, testFunction, prepareReturnValue, callback)
118 var now = window.performance && window.performance.now ? function () { return window.performance.now(); } : Date.now;
120 var contentWindow = this._frame.contentWindow;
121 var contentDocument = this._frame.contentDocument;
123 var startTime = now();
124 testFunction(prepareReturnValue, contentWindow, contentDocument);
126 var syncTime = endTime - startTime;
128 var startTime = now();
129 setTimeout(function () {
131 callback(syncTime, endTime - startTime);
135 function BenchmarkState(suites) {
136 this._suites = suites;
137 this._suiteIndex = -1;
142 BenchmarkState.prototype.currentSuite = function() {
143 return this._suites[this._suiteIndex];
146 BenchmarkState.prototype.currentTest = function () {
147 var suite = this.currentSuite();
148 return suite ? suite.tests[this._testIndex] : null;
151 BenchmarkState.prototype.next = function () {
154 var suite = this._suites[this._suiteIndex];
155 if (suite && this._testIndex < suite.tests.length)
161 } while (this._suiteIndex < this._suites.length && this._suites[this._suiteIndex].disabled);
166 BenchmarkState.prototype.isFirstTest = function () {
167 return !this._testIndex;
170 BenchmarkState.prototype.prepareCurrentSuite = function (runner, frame) {
171 var suite = this.currentSuite();
172 var promise = new SimplePromise;
173 frame.onload = function () {
174 suite.prepare(runner, frame.contentWindow, frame.contentDocument).then(function (result) { promise.resolve(result); });
176 frame.src = 'resources/' + suite.url;
180 BenchmarkRunner.prototype.step = function (state) {
182 state = new BenchmarkState(this._suites);
183 this._measuredValues = {tests: {}, total: 0};
186 var suite = state.currentSuite();
189 var promise = new SimplePromise;
194 if (state.isFirstTest()) {
195 this._masuredValuesForCurrentSuite = {};
197 return state.prepareCurrentSuite(this, this._appendFrame()).then(function (prepareReturnValue) {
198 self._prepareReturnValue = prepareReturnValue;
199 return self._runTestAndRecordResults(state);
203 return this._runTestAndRecordResults(state);
206 BenchmarkRunner.prototype.runAllSteps = function (startingState) {
207 var nextCallee = this.runAllSteps.bind(this);
208 this.step(startingState).then(function (nextState) {
210 nextCallee(nextState);
214 BenchmarkRunner.prototype.runMultipleIterations = function (iterationCount) {
216 var currentIteration = 0;
218 this._runNextIteration = function () {
220 if (currentIteration < iterationCount)
222 else if (this._client && this._client.didFinishLastIteration)
223 this._client.didFinishLastIteration();
226 if (this._client && this._client.willStartFirstIteration)
227 this._client.willStartFirstIteration(iterationCount);
232 BenchmarkRunner.prototype._runTestAndRecordResults = function (state) {
233 var promise = new SimplePromise;
234 var suite = state.currentSuite();
235 var test = state.currentTest();
237 if (this._client && this._client.willRunTest)
238 this._client.willRunTest(suite, test);
241 setTimeout(function () {
242 self._runTest(suite, test.run, self._prepareReturnValue, function (syncTime, asyncTime) {
243 var suiteResults = self._measuredValues.tests[suite.name] || {tests:{}, total: 0};
244 var total = syncTime + asyncTime;
245 self._measuredValues.tests[suite.name] = suiteResults;
246 suiteResults.tests[test.name] = {tests: {'Sync': syncTime, 'Async': asyncTime}, total: total};
247 suiteResults.total += total;
248 self._measuredValues.total += total;
250 if (self._client && self._client.didRunTest)
251 self._client.didRunTest(suite, test);
254 if (state.currentSuite() != suite)
256 promise.resolve(state);
262 BenchmarkRunner.prototype._finalize = function () {
265 if (this._client && this._client.didRunSuites)
266 this._client.didRunSuites(this._measuredValues);
268 if (this._runNextIteration)
269 this._runNextIteration();