diff options
author | vitalyr@chromium.org <vitalyr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-07 09:00:47 +0000 |
---|---|---|
committer | vitalyr@chromium.org <vitalyr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-07 09:00:47 +0000 |
commit | 7a158cc250768c944236b31042aa06d55757f72f (patch) | |
tree | c5396866aac95255801bfa07c404ce78f5375048 /tools/playback_benchmark/common.js | |
parent | 1d21e4402d5f87766399afb56b20964af3f8a64e (diff) | |
download | chromium_src-7a158cc250768c944236b31042aa06d55757f72f.zip chromium_src-7a158cc250768c944236b31042aa06d55757f72f.tar.gz chromium_src-7a158cc250768c944236b31042aa06d55757f72f.tar.bz2 |
Landing for Pavel Podivilov (podivilov@chromium.org).
Playback benchmark scripts.
Original review: http://codereview.chromium.org/1515006/show
BUG=none
TEST=none
TBR=podivilov
Review URL: http://codereview.chromium.org/2626002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@49041 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/playback_benchmark/common.js')
-rw-r--r-- | tools/playback_benchmark/common.js | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/tools/playback_benchmark/common.js b/tools/playback_benchmark/common.js new file mode 100644 index 0000000..801d602 --- /dev/null +++ b/tools/playback_benchmark/common.js @@ -0,0 +1,318 @@ +// Copyright 2010 Google Inc. All Rights Reserved. + +/** + * @fileoverview Classes and functions used during recording and playback. + */ + +var Benchmark = Benchmark || {}; + +Benchmark.functionList = [ + ['setTimeout', 'setTimeout'], + ['clearTimeout', 'clearTimeout'], + ['setInterval', 'setInterval'], + ['clearInterval', 'clearInterval'], + ['XMLHttpRequest', 'XMLHttpRequest'], + ['addEventListenerToWindow', 'addEventListener'], + ['addEventListenerToNode', 'addEventListener', ['Node', 'prototype']], + ['removeEventListenerFromNode', 'removeEventListener', ['Node', 'prototype']], + ['addEventListenerToXHR', 'addEventListener', + ['XMLHttpRequest', 'prototype']], + ['random', 'random', ['Math']], + ['Date', 'Date'], + ['documentWriteln', 'writeln', ['document']], + ['documentWrite', 'write', ['document']] +]; + +Benchmark.timeoutMapping = []; + +Benchmark.ignoredListeners = ['mousemove', 'mouseover', 'mouseout']; + +Benchmark.originals = {}; + +Benchmark.overrides = { + setTimeout: function(callback, timeout) { + var event = {type: 'timeout', timeout: timeout}; + var eventId = Benchmark.agent.createAsyncEvent(event); + var timerId = Benchmark.originals.setTimeout.call(this, function() { + Benchmark.agent.fireAsyncEvent(eventId, callback); + }, Benchmark.playback ? 0 : timeout); + Benchmark.timeoutMapping[timerId] = eventId; + return timerId; + }, + + clearTimeout: function(timerId) { + var eventId = Benchmark.timeoutMapping[timerId]; + if (eventId == undefined) return; + Benchmark.agent.cancelAsyncEvent(eventId); + Benchmark.originals.clearTimeout.call(this, timerId); + }, + + setInterval: function(callback, timeout) { + console.warn('setInterval'); + }, + + clearInterval: function(timerId) { + console.warn('clearInterval'); + }, + + XMLHttpRequest: function() { + return new Benchmark.XMLHttpRequestWrapper(); + }, + + addEventListener: function(type, listener, useCapture, target, targetType, + originalFunction) { + var event = {type: 'addEventListener', target: targetType, eventType: type}; + var eventId = Benchmark.agent.createAsyncEvent(event); + listener.eventId = eventId; + listener.wrapper = function(e) { + Benchmark.agent.fireAsyncEvent(eventId, function() { + listener.call(target, e); + }); + }; + originalFunction.call(target, type, listener.wrapper, useCapture); + }, + + addEventListenerToWindow: function(type, listener, useCapture) { + if (Benchmark.ignoredListeners.indexOf(type) != -1) return; + Benchmark.overrides.addEventListener( + type, listener, useCapture, this, 'window', + Benchmark.originals.addEventListenerToWindow); + }, + + addEventListenerToNode: function(type, listener, useCapture) { + if (Benchmark.ignoredListeners.indexOf(type) != -1) return; + Benchmark.overrides.addEventListener( + type, listener, useCapture, this, 'node', + Benchmark.originals.addEventListenerToNode); + }, + + addEventListenerToXHR: function(type, listener, useCapture) { + Benchmark.overrides.addEventListener( + type, listener, useCapture, this, 'xhr', + Benchmark.originals.addEventListenerToXHR); + }, + + removeEventListener: function(type, listener, useCapture, target, + originalFunction) { + Benchmark.agent.cancelAsyncEvent(listener.eventId); + originalFunction.call(target, listener.wrapper, useCapture); + }, + + removeEventListenerFromWindow: function(type, listener, useCapture) { + removeEventListener(type, listener, useCapture, this, + Benchmark.originals.removeEventListenerFromWindow); + }, + + removeEventListenerFromNode: function(type, listener, useCapture) { + removeEventListener(type, listener, useCapture, this, + Benchmark.originals.removeEventListenerFromNode); + }, + + removeEventListenerFromXHR: function(type, listener, useCapture) { + removeEventListener(type, listener, useCapture, this, + Benchmark.originals.removeEventListenerFromXHR); + }, + + random: function() { + return Benchmark.agent.random(); + }, + + Date: function() { + var a = arguments; + var D = Benchmark.originals.Date, d; + switch(a.length) { + case 0: d = new D(Benchmark.agent.dateNow()); break; + case 1: d = new D(a[0]); break; + case 2: d = new D(a[0], a[1]); break; + case 3: d = new D(a[0], a[1], a[2]); break; + default: Benchmark.die('window.Date', arguments); + } + d.getTimezoneOffset = function() { return -240; }; + return d; + }, + + dateNow: function() { + return Benchmark.agent.dateNow(); + }, + + documentWriteln: function() { + console.warn('writeln'); + }, + + documentWrite: function() { + console.warn('write'); + } +}; + +/** + * Replaces window functions specified by Benchmark.functionList with overrides + * and optionally saves original functions to Benchmark.originals. + * @param {Object} wnd Window object. + * @param {boolean} storeOriginals When true, original functions are saved to + * Benchmark.originals. + */ +Benchmark.installOverrides = function(wnd, storeOriginals) { + // Substitute window functions with overrides. + for (var i = 0; i < Benchmark.functionList.length; ++i) { + var info = Benchmark.functionList[i], object = wnd; + var propertyName = info[1], pathToProperty = info[2]; + if (pathToProperty) + for (var j = 0; j < pathToProperty.length; ++j) + object = object[pathToProperty[j]]; + if (storeOriginals) + Benchmark.originals[info[0]] = object[propertyName]; + object[propertyName] = Benchmark.overrides[info[0]]; + } + wnd.__defineSetter__('onload', function() { + console.warn('window.onload setter')} + ); + + // Substitute window functions of static frames when DOM content is loaded. + Benchmark.originals.addEventListenerToWindow.call(wnd, 'DOMContentLoaded', + function() { + var frames = document.getElementsByTagName('iframe'); + for (var i = 0, frame; frame = frames[i]; ++i) { + Benchmark.installOverrides(frame.contentWindow); + } + }, true); + + // Substitute window functions of dynamically added frames. + Benchmark.originals.addEventListenerToWindow.call( + wnd, 'DOMNodeInsertedIntoDocument', function(e) { + if (e.target.tagName && e.target.tagName.toLowerCase() != 'iframe') + return; + if (e.target.contentWindow) + Benchmark.installOverrides(e.target.contentWindow); + }, true); +}; + +// Install overrides on top window. +Benchmark.installOverrides(window, true); + +/** + * window.XMLHttpRequest wrapper. Notifies Benchmark.agent when request is + * opened, aborted, and when it's ready state changes to DONE. + * @constructor + */ +Benchmark.XMLHttpRequestWrapper = function() { + this.request = new Benchmark.originals.XMLHttpRequest(); + this.wrapperReadyState = 0; +}; + +// Create XMLHttpRequestWrapper functions and property accessors using original +// ones. +(function() { + var request = new Benchmark.originals.XMLHttpRequest(); + for (var property in request) { + if (property === 'channel') continue; // Quick fix for FF. + if (typeof(request[property]) == 'function') { + (function(property) { + var f = Benchmark.originals.XMLHttpRequest.prototype[property]; + Benchmark.XMLHttpRequestWrapper.prototype[property] = function() { + f.apply(this.request, arguments); + }; + })(property); + } else { + (function(property) { + Benchmark.XMLHttpRequestWrapper.prototype.__defineGetter__(property, + function() { return this.request[property]; }); + Benchmark.XMLHttpRequestWrapper.prototype.__defineSetter__(property, + function(value) { + this.request[property] = value; + }); + + })(property); + } + } +})(); + +// Define onreadystatechange getter. +Benchmark.XMLHttpRequestWrapper.prototype.__defineGetter__('onreadystatechange', + function() { return this.clientOnReadyStateChange; }); + +// Define onreadystatechange setter. +Benchmark.XMLHttpRequestWrapper.prototype.__defineSetter__('onreadystatechange', + function(value) { this.clientOnReadyStateChange = value; }); + +Benchmark.XMLHttpRequestWrapper.prototype.__defineGetter__('readyState', + function() { return this.wrapperReadyState; }); + +Benchmark.XMLHttpRequestWrapper.prototype.__defineSetter__('readyState', + function() {}); + + +/** + * Wrapper for XMLHttpRequest.open. + */ +Benchmark.XMLHttpRequestWrapper.prototype.open = function() { + var url = Benchmark.extractURL(arguments[1]); + var event = {type: 'request', method: arguments[0], url: url}; + this.eventId = Benchmark.agent.createAsyncEvent(event); + + var request = this.request; + var requestWrapper = this; + Benchmark.originals.XMLHttpRequest.prototype.open.apply(request, arguments); + request.onreadystatechange = function() { + if (this.readyState != 4 || requestWrapper.cancelled) return; + var callback = requestWrapper.clientOnReadyStateChange || function() {}; + Benchmark.agent.fireAsyncEvent(requestWrapper.eventId, function() { + requestWrapper.wrapperReadyState = 4; + callback.call(request); + }); + } +}; + +/** + * Wrapper for XMLHttpRequest.abort. + */ +Benchmark.XMLHttpRequestWrapper.prototype.abort = function() { + this.cancelled = true; + Benchmark.originals.XMLHttpRequest.prototype.abort.apply( + this.request, arguments); + Benchmark.agent.cancelAsyncEvent(this.eventId); +}; + +/** + * Driver url for reporting results. + * @const {string} + */ +Benchmark.DRIVER_URL = '/benchmark/'; + +/** + * Posts request as json to Benchmark.DRIVER_URL. + * @param {Object} request Request to post. + */ +Benchmark.post = function(request, async) { + if (async === undefined) async = true; + var xmlHttpRequest = new Benchmark.originals.XMLHttpRequest(); + xmlHttpRequest.open("POST", Benchmark.DRIVER_URL, async); + xmlHttpRequest.setRequestHeader("Content-type", "application/json"); + xmlHttpRequest.send(JSON.stringify(request)); +}; + +/** + * Extracts url string. + * @param {(string|Object)} url Object or string representing url. + * @return {string} Extracted url. + */ +Benchmark.extractURL = function(url) { + if (typeof(url) == 'string') return url; + return url.nI || url.G || ''; +}; + + +/** + * Logs error message to console and throws an exception. + * @param {string} message Error message + */ +Benchmark.die = function(message) { + // Debugging stuff. + var position = top.Benchmark.playback ? top.Benchmark.agent.timelinePosition : + top.Benchmark.agent.timeline.length; + message = message + ' at position ' + position; + console.error(message); + Benchmark.post({error: message}); + console.log(Benchmark.originals.setTimeout.call(window, function() {}, 9999)); + try { (0)() } catch(ex) { console.error(ex.stack); } + throw message; +};
\ No newline at end of file |