summaryrefslogtreecommitdiffstats
path: root/tools/playback_benchmark/common.js
diff options
context:
space:
mode:
authorvitalyr@chromium.org <vitalyr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-07 09:00:47 +0000
committervitalyr@chromium.org <vitalyr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-07 09:00:47 +0000
commit7a158cc250768c944236b31042aa06d55757f72f (patch)
treec5396866aac95255801bfa07c404ce78f5375048 /tools/playback_benchmark/common.js
parent1d21e4402d5f87766399afb56b20964af3f8a64e (diff)
downloadchromium_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.js318
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