diff options
author | Brian White <mscdex@mscdex.net> | 2015-05-01 14:08:02 -0400 |
---|---|---|
committer | Brian White <mscdex@mscdex.net> | 2015-05-01 21:27:34 -0400 |
commit | c7782c0af8a4e4ee26da6e44e07c3987d9d3ddb6 (patch) | |
tree | c34ab5332254a02afdfa73476c5ce742da981dca /src | |
parent | ea5195ccaf6d51262c9089c2ec5c6f5634bc12b5 (diff) | |
download | android-node-v8-c7782c0af8a4e4ee26da6e44e07c3987d9d3ddb6.tar.gz android-node-v8-c7782c0af8a4e4ee26da6e44e07c3987d9d3ddb6.tar.bz2 android-node-v8-c7782c0af8a4e4ee26da6e44e07c3987d9d3ddb6.zip |
node: improve nextTick performance
This commit uses separate functions to isolate deopts caused by
try-catches and avoids fn.apply() for callbacks with small numbers
of arguments.
These changes improve performance by ~1-40% in the various
nextTick benchmarks.
PR-URL: https://github.com/iojs/io.js/pull/1571
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/node.js | 121 |
1 files changed, 99 insertions, 22 deletions
diff --git a/src/node.js b/src/node.js index 1cb71c4927..5cf56f6242 100644 --- a/src/node.js +++ b/src/node.js @@ -328,22 +328,33 @@ // Run callbacks that have no domain. // Using domains will cause this to be overridden. function _tickCallback() { - var callback, threw, tock; + var callback, args, tock; do { while (tickInfo[kIndex] < tickInfo[kLength]) { tock = nextTickQueue[tickInfo[kIndex]++]; callback = tock.callback; - threw = true; - try { - if (tock.args === undefined) - callback(); - else - callback.apply(null, tock.args); - threw = false; - } finally { - if (threw) - tickDone(); + args = tock.args; + // Using separate callback execution functions helps to limit the + // scope of DEOPTs caused by using try blocks and allows direct + // callback invocation with small numbers of arguments to avoid the + // performance hit associated with using `fn.apply()` + if (args === undefined) { + doNTCallback0(callback); + } else { + switch (args.length) { + case 1: + doNTCallback1(callback, args[0]); + break; + case 2: + doNTCallback2(callback, args[0], args[1]); + break; + case 3: + doNTCallback3(callback, args[0], args[1], args[2]); + break; + default: + doNTCallbackMany(callback, args); + } } if (1e4 < tickInfo[kIndex]) tickDone(); @@ -355,25 +366,36 @@ } function _tickDomainCallback() { - var callback, domain, threw, tock; + var callback, domain, args, tock; do { while (tickInfo[kIndex] < tickInfo[kLength]) { tock = nextTickQueue[tickInfo[kIndex]++]; callback = tock.callback; domain = tock.domain; + args = tock.args; if (domain) domain.enter(); - threw = true; - try { - if (tock.args === undefined) - callback(); - else - callback.apply(null, tock.args); - threw = false; - } finally { - if (threw) - tickDone(); + // Using separate callback execution functions helps to limit the + // scope of DEOPTs caused by using try blocks and allows direct + // callback invocation with small numbers of arguments to avoid the + // performance hit associated with using `fn.apply()` + if (args === undefined) { + doNTCallback0(callback); + } else { + switch (args.length) { + case 1: + doNTCallback1(callback, args[0]); + break; + case 2: + doNTCallback2(callback, args[0], args[1]); + break; + case 3: + doNTCallback3(callback, args[0], args[1], args[2]); + break; + default: + doNTCallbackMany(callback, args); + } } if (1e4 < tickInfo[kIndex]) tickDone(); @@ -386,6 +408,61 @@ } while (tickInfo[kLength] !== 0); } + function doNTCallback0(callback) { + var threw = true; + try { + callback(); + threw = false; + } finally { + if (threw) + tickDone(); + } + } + + function doNTCallback1(callback, arg1) { + var threw = true; + try { + callback(arg1); + threw = false; + } finally { + if (threw) + tickDone(); + } + } + + function doNTCallback2(callback, arg1, arg2) { + var threw = true; + try { + callback(arg1, arg2); + threw = false; + } finally { + if (threw) + tickDone(); + } + } + + function doNTCallback3(callback, arg1, arg2, arg3) { + var threw = true; + try { + callback(arg1, arg2, arg3); + threw = false; + } finally { + if (threw) + tickDone(); + } + } + + function doNTCallbackMany(callback, args) { + var threw = true; + try { + callback.apply(null, args); + threw = false; + } finally { + if (threw) + tickDone(); + } + } + function TickObject(c, args) { this.callback = c; this.domain = process.domain || null; |