You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2013/12/20 05:13:26 UTC
spec commit: Use setImmediate in exec bridge benchmark instead of
setTimeout.
Updated Branches:
refs/heads/master 7e771d58f -> f01dcadcf
Use setImmediate in exec bridge benchmark instead of setTimeout.
The artificial delay of setTimeout turned out to be affecting timings.
Project: http://git-wip-us.apache.org/repos/asf/cordova-mobile-spec/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-mobile-spec/commit/f01dcadc
Tree: http://git-wip-us.apache.org/repos/asf/cordova-mobile-spec/tree/f01dcadc
Diff: http://git-wip-us.apache.org/repos/asf/cordova-mobile-spec/diff/f01dcadc
Branch: refs/heads/master
Commit: f01dcadcfabca3c80c6ff9073464d4cdfe989562
Parents: 7e771d5
Author: Andrew Grieve <ag...@chromium.org>
Authored: Thu Dec 19 23:12:14 2013 -0500
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Thu Dec 19 23:12:14 2013 -0500
----------------------------------------------------------------------
benchmarks/index.html | 9 +-
benchmarks/setImmediate.js | 218 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 223 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-mobile-spec/blob/f01dcadc/benchmarks/index.html
----------------------------------------------------------------------
diff --git a/benchmarks/index.html b/benchmarks/index.html
index 91b3fea..8941167 100644
--- a/benchmarks/index.html
+++ b/benchmarks/index.html
@@ -27,8 +27,8 @@
<meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
<title>Cordova Mobile Spec</title>
<link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
- <script type="text/javascript" charset="utf-8" src="../cordova-incl.js"></script>
-
+ <script src="../cordova-incl.js"></script>
+ <script src="setImmediate.js"></script>
<script>
var exec = cordova.require('cordova/exec'),
appLogElem = null,
@@ -68,7 +68,7 @@
var elapsedMs = new Date - startTime;
if (elapsedMs < durationMs) {
if (useSetTimeout) {
- setTimeout(echoMessage, 0);
+ setImmediate(echoMessage);
} else {
echoMessage();
}
@@ -148,12 +148,13 @@
<li>ENABLE_LOCATION_CHANGE_EXEC_MODE = true
<li>DISABLE_EXEC_CHAINING = true
</ul>
+ As of iOS 7.0.2, Andrew found that the iframe bridge is still the fastest on iOS.
<fieldset>
<legend>Settings</legend>
<label>Test Duration: <select id="test-duration"><option>1 Second</option><option>5 Seconds</option></select><br></label>
<label style="display:none">JS->Native Bridge Mode: <select id="js-native-modes"></select><br></label>
<label style="display:none">Native->JS Bridge Mode: <select id="native-js-modes"></select><br></label>
- <label><input type="checkbox" id="use-setTimeout"> Force async JS->Native</label><br>
+ <label><input type="checkbox" id="use-setTimeout"> Force async JS->Native (avoids evalAndFetch optimization on iOS)</label><br>
<label><input type="checkbox" id="async-echo"> Force async Native->JS</label><br>
<label>Payload size (in 100s of bytes) <input id="payload-size" value="5" style="width:100px"></label><br>
<button onclick="benchExec()">Benchmark exec</button><br>
http://git-wip-us.apache.org/repos/asf/cordova-mobile-spec/blob/f01dcadc/benchmarks/setImmediate.js
----------------------------------------------------------------------
diff --git a/benchmarks/setImmediate.js b/benchmarks/setImmediate.js
new file mode 100644
index 0000000..f034bb4
--- /dev/null
+++ b/benchmarks/setImmediate.js
@@ -0,0 +1,218 @@
+(function (global, undefined) {
+ "use strict";
+
+ var tasks = (function () {
+ function Task(handler, args) {
+ this.handler = handler;
+ this.args = args;
+ }
+ Task.prototype.run = function () {
+ // See steps in section 5 of the spec.
+ if (typeof this.handler === "function") {
+ // Choice of `thisArg` is not in the setImmediate spec; `undefined` is in the setTimeout spec though:
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html
+ this.handler.apply(undefined, this.args);
+ } else {
+ var scriptSource = "" + this.handler;
+ /*jshint evil: true */
+ eval(scriptSource);
+ }
+ };
+
+ var nextHandle = 1; // Spec says greater than zero
+ var tasksByHandle = {};
+ var currentlyRunningATask = false;
+
+ return {
+ addFromSetImmediateArguments: function (args) {
+ var handler = args[0];
+ var argsToHandle = Array.prototype.slice.call(args, 1);
+ var task = new Task(handler, argsToHandle);
+
+ var thisHandle = nextHandle++;
+ tasksByHandle[thisHandle] = task;
+ return thisHandle;
+ },
+ runIfPresent: function (handle) {
+ // From the spec: "Wait until any invocations of this algorithm started before this one have completed."
+ // So if we're currently running a task, we'll need to delay this invocation.
+ if (!currentlyRunningATask) {
+ var task = tasksByHandle[handle];
+ if (task) {
+ currentlyRunningATask = true;
+ try {
+ task.run();
+ } finally {
+ delete tasksByHandle[handle];
+ currentlyRunningATask = false;
+ }
+ }
+ } else {
+ // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a
+ // "too much recursion" error.
+ global.setTimeout(function () {
+ tasks.runIfPresent(handle);
+ }, 0);
+ }
+ },
+ remove: function (handle) {
+ delete tasksByHandle[handle];
+ }
+ };
+ }());
+
+ function canUseNextTick() {
+ // Don't get fooled by e.g. browserify environments.
+ return typeof process === "object" &&
+ Object.prototype.toString.call(process) === "[object process]";
+ }
+
+ function canUseMessageChannel() {
+ return !!global.MessageChannel;
+ }
+
+ function canUsePostMessage() {
+ // The test against `importScripts` prevents this implementation from being installed inside a web worker,
+ // where `global.postMessage` means something completely different and can't be used for this purpose.
+
+ if (!global.postMessage || global.importScripts) {
+ return false;
+ }
+
+ var postMessageIsAsynchronous = true;
+ var oldOnMessage = global.onmessage;
+ global.onmessage = function () {
+ postMessageIsAsynchronous = false;
+ };
+ global.postMessage("", "*");
+ global.onmessage = oldOnMessage;
+
+ return postMessageIsAsynchronous;
+ }
+
+ function canUseReadyStateChange() {
+ return "document" in global && "onreadystatechange" in global.document.createElement("script");
+ }
+
+ function installNextTickImplementation(attachTo) {
+ attachTo.setImmediate = function () {
+ var handle = tasks.addFromSetImmediateArguments(arguments);
+
+ process.nextTick(function () {
+ tasks.runIfPresent(handle);
+ });
+
+ return handle;
+ };
+ }
+
+ function installMessageChannelImplementation(attachTo) {
+ var channel = new global.MessageChannel();
+ channel.port1.onmessage = function (event) {
+ var handle = event.data;
+ tasks.runIfPresent(handle);
+ };
+ attachTo.setImmediate = function () {
+ var handle = tasks.addFromSetImmediateArguments(arguments);
+
+ channel.port2.postMessage(handle);
+
+ return handle;
+ };
+ }
+
+ function installPostMessageImplementation(attachTo) {
+ // Installs an event handler on `global` for the `message` event: see
+ // * https://developer.mozilla.org/en/DOM/window.postMessage
+ // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
+
+ var MESSAGE_PREFIX = "com.bn.NobleJS.setImmediate" + Math.random();
+
+ function isStringAndStartsWith(string, putativeStart) {
+ return typeof string === "string" && string.substring(0, putativeStart.length) === putativeStart;
+ }
+
+ function onGlobalMessage(event) {
+ // This will catch all incoming messages (even from other windows!), so we need to try reasonably hard to
+ // avoid letting anyone else trick us into firing off. We test the origin is still this window, and that a
+ // (randomly generated) unpredictable identifying prefix is present.
+ if (event.source === global && isStringAndStartsWith(event.data, MESSAGE_PREFIX)) {
+ var handle = event.data.substring(MESSAGE_PREFIX.length);
+ tasks.runIfPresent(handle);
+ }
+ }
+ if (global.addEventListener) {
+ global.addEventListener("message", onGlobalMessage, false);
+ } else {
+ global.attachEvent("onmessage", onGlobalMessage);
+ }
+
+ attachTo.setImmediate = function () {
+ var handle = tasks.addFromSetImmediateArguments(arguments);
+
+ // Make `global` post a message to itself with the handle and identifying prefix, thus asynchronously
+ // invoking our onGlobalMessage listener above.
+ global.postMessage(MESSAGE_PREFIX + handle, "*");
+
+ return handle;
+ };
+ }
+
+ function installReadyStateChangeImplementation(attachTo) {
+ attachTo.setImmediate = function () {
+ var handle = tasks.addFromSetImmediateArguments(arguments);
+
+ // Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
+ // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
+ var scriptEl = global.document.createElement("script");
+ scriptEl.onreadystatechange = function () {
+ tasks.runIfPresent(handle);
+
+ scriptEl.onreadystatechange = null;
+ scriptEl.parentNode.removeChild(scriptEl);
+ scriptEl = null;
+ };
+ global.document.documentElement.appendChild(scriptEl);
+
+ return handle;
+ };
+ }
+
+ function installSetTimeoutImplementation(attachTo) {
+ attachTo.setImmediate = function () {
+ var handle = tasks.addFromSetImmediateArguments(arguments);
+
+ global.setTimeout(function () {
+ tasks.runIfPresent(handle);
+ }, 0);
+
+ return handle;
+ };
+ }
+
+ if (!global.setImmediate) {
+ // If supported, we should attach to the prototype of global, since that is where setTimeout et al. live.
+ var attachTo = typeof Object.getPrototypeOf === "function" && "setTimeout" in Object.getPrototypeOf(global) ?
+ Object.getPrototypeOf(global)
+ : global;
+
+ if (canUseNextTick()) {
+ // For Node.js before 0.9
+ installNextTickImplementation(attachTo);
+ } else if (canUsePostMessage()) {
+ // For non-IE10 modern browsers
+ installPostMessageImplementation(attachTo);
+ } else if (canUseMessageChannel()) {
+ // For web workers, where supported
+ installMessageChannelImplementation(attachTo);
+ } else if (canUseReadyStateChange()) {
+ // For IE 6–8
+ installReadyStateChangeImplementation(attachTo);
+ } else {
+ // For older browsers
+ installSetTimeoutImplementation(attachTo);
+ }
+
+ attachTo.clearImmediate = tasks.remove;
+ }
+}(typeof global === "object" && global ? global : this));