Browse Source

node: improve process.nextTick performance

Prevent deoptimization of process.nextTick by removing the try finally
block. This is not necessary as the next tick queue will be reset
anyway, no matter if the callback throws or not.

Use a predefined array size prevents resizing the array and is therefor
faster.

PR-URL: https://github.com/nodejs/node/pull/5092
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
process-exit-stdio-flushing
Ruben Bridgewater 9 years ago
committed by Trevor Norris
parent
commit
88307974e6
  1. 121
      src/node.js
  2. 8
      test/message/eval_messages.out
  3. 2
      test/message/nexttick_throw.out
  4. 8
      test/message/stdin_messages.out

121
src/node.js

@ -374,37 +374,40 @@
scheduleMicrotasks(); scheduleMicrotasks();
} }
// Run callbacks that have no domain. function _combinedTickCallback(args, callback) {
// Using domains will cause this to be overridden.
function _tickCallback() {
var callback, args, tock;
do {
while (tickInfo[kIndex] < tickInfo[kLength]) {
tock = nextTickQueue[tickInfo[kIndex]++];
callback = tock.callback;
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) { if (args === undefined) {
nextTickCallbackWith0Args(callback); callback();
} else { } else {
switch (args.length) { switch (args.length) {
case 1: case 1:
nextTickCallbackWith1Arg(callback, args[0]); callback(args[0]);
break; break;
case 2: case 2:
nextTickCallbackWith2Args(callback, args[0], args[1]); callback(args[0], args[1]);
break; break;
case 3: case 3:
nextTickCallbackWith3Args(callback, args[0], args[1], args[2]); callback(args[0], args[1], args[2]);
break; break;
default: default:
nextTickCallbackWithManyArgs(callback, args); callback.apply(null, args);
}
} }
} }
// Run callbacks that have no domain.
// Using domains will cause this to be overridden.
function _tickCallback() {
var callback, args, tock;
do {
while (tickInfo[kIndex] < tickInfo[kLength]) {
tock = nextTickQueue[tickInfo[kIndex]++];
callback = tock.callback;
args = tock.args;
// Using separate callback execution functions allows direct
// callback invocation with small numbers of arguments to avoid the
// performance hit associated with using `fn.apply()`
_combinedTickCallback(args, callback);
if (1e4 < tickInfo[kIndex]) if (1e4 < tickInfo[kIndex])
tickDone(); tickDone();
} }
@ -425,27 +428,10 @@
args = tock.args; args = tock.args;
if (domain) if (domain)
domain.enter(); domain.enter();
// Using separate callback execution functions helps to limit the // Using separate callback execution functions allows direct
// scope of DEOPTs caused by using try blocks and allows direct
// callback invocation with small numbers of arguments to avoid the // callback invocation with small numbers of arguments to avoid the
// performance hit associated with using `fn.apply()` // performance hit associated with using `fn.apply()`
if (args === undefined) { _combinedTickCallback(args, callback);
nextTickCallbackWith0Args(callback);
} else {
switch (args.length) {
case 1:
nextTickCallbackWith1Arg(callback, args[0]);
break;
case 2:
nextTickCallbackWith2Args(callback, args[0], args[1]);
break;
case 3:
nextTickCallbackWith3Args(callback, args[0], args[1], args[2]);
break;
default:
nextTickCallbackWithManyArgs(callback, args);
}
}
if (1e4 < tickInfo[kIndex]) if (1e4 < tickInfo[kIndex])
tickDone(); tickDone();
if (domain) if (domain)
@ -457,61 +443,6 @@
} while (tickInfo[kLength] !== 0); } while (tickInfo[kLength] !== 0);
} }
function nextTickCallbackWith0Args(callback) {
var threw = true;
try {
callback();
threw = false;
} finally {
if (threw)
tickDone();
}
}
function nextTickCallbackWith1Arg(callback, arg1) {
var threw = true;
try {
callback(arg1);
threw = false;
} finally {
if (threw)
tickDone();
}
}
function nextTickCallbackWith2Args(callback, arg1, arg2) {
var threw = true;
try {
callback(arg1, arg2);
threw = false;
} finally {
if (threw)
tickDone();
}
}
function nextTickCallbackWith3Args(callback, arg1, arg2, arg3) {
var threw = true;
try {
callback(arg1, arg2, arg3);
threw = false;
} finally {
if (threw)
tickDone();
}
}
function nextTickCallbackWithManyArgs(callback, args) {
var threw = true;
try {
callback.apply(null, args);
threw = false;
} finally {
if (threw)
tickDone();
}
}
function TickObject(c, args) { function TickObject(c, args) {
this.callback = c; this.callback = c;
this.domain = process.domain || null; this.domain = process.domain || null;
@ -527,9 +458,9 @@
var args; var args;
if (arguments.length > 1) { if (arguments.length > 1) {
args = []; args = new Array(arguments.length - 1);
for (var i = 1; i < arguments.length; i++) for (var i = 1; i < arguments.length; i++)
args.push(arguments[i]); args[i - 1] = arguments[i];
} }
nextTickQueue.push(new TickObject(callback, args)); nextTickQueue.push(new TickObject(callback, args));

8
test/message/eval_messages.out

@ -7,7 +7,7 @@ SyntaxError: Strict mode code may not include a with statement
at Object.<anonymous> ([eval]-wrapper:*:*) at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (module.js:*:*) at Module._compile (module.js:*:*)
at node.js:*:* at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*) at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*) at process._tickCallback (node.js:*:*)
42 42
42 42
@ -20,7 +20,7 @@ Error: hello
at Object.<anonymous> ([eval]-wrapper:*:*) at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (module.js:*:*) at Module._compile (module.js:*:*)
at node.js:*:* at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*) at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*) at process._tickCallback (node.js:*:*)
[eval]:1 [eval]:1
throw new Error("hello") throw new Error("hello")
@ -31,7 +31,7 @@ Error: hello
at Object.<anonymous> ([eval]-wrapper:*:*) at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (module.js:*:*) at Module._compile (module.js:*:*)
at node.js:*:* at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*) at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*) at process._tickCallback (node.js:*:*)
100 100
[eval]:1 [eval]:1
@ -43,7 +43,7 @@ ReferenceError: y is not defined
at Object.<anonymous> ([eval]-wrapper:*:*) at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (module.js:*:*) at Module._compile (module.js:*:*)
at node.js:*:* at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*) at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*) at process._tickCallback (node.js:*:*)
[eval]:1 [eval]:1
var ______________________________________________; throw 10 var ______________________________________________; throw 10

2
test/message/nexttick_throw.out

@ -4,7 +4,7 @@
^ ^
ReferenceError: undefined_reference_error_maker is not defined ReferenceError: undefined_reference_error_maker is not defined
at *test*message*nexttick_throw.js:*:* at *test*message*nexttick_throw.js:*:*
at nextTickCallbackWith0Args (node.js:*:*) at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*) at process._tickCallback (node.js:*:*)
at Function.Module.runMain (module.js:*:*) at Function.Module.runMain (module.js:*:*)
at startup (node.js:*:*) at startup (node.js:*:*)

8
test/message/stdin_messages.out

@ -8,7 +8,7 @@ SyntaxError: Strict mode code may not include a with statement
at Object.<anonymous> ([stdin]-wrapper:*:*) at Object.<anonymous> ([stdin]-wrapper:*:*)
at Module._compile (module.js:*:*) at Module._compile (module.js:*:*)
at node.js:*:* at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*) at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*) at process._tickCallback (node.js:*:*)
42 42
42 42
@ -22,7 +22,7 @@ Error: hello
at Object.<anonymous> ([stdin]-wrapper:*:*) at Object.<anonymous> ([stdin]-wrapper:*:*)
at Module._compile (module.js:*:*) at Module._compile (module.js:*:*)
at node.js:*:* at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*) at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*) at process._tickCallback (node.js:*:*)
[stdin]:1 [stdin]:1
@ -34,7 +34,7 @@ Error: hello
at Object.<anonymous> ([stdin]-wrapper:*:*) at Object.<anonymous> ([stdin]-wrapper:*:*)
at Module._compile (module.js:*:*) at Module._compile (module.js:*:*)
at node.js:*:* at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*) at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*) at process._tickCallback (node.js:*:*)
100 100
@ -47,7 +47,7 @@ ReferenceError: y is not defined
at Object.<anonymous> ([stdin]-wrapper:*:*) at Object.<anonymous> ([stdin]-wrapper:*:*)
at Module._compile (module.js:*:*) at Module._compile (module.js:*:*)
at node.js:*:* at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*) at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*) at process._tickCallback (node.js:*:*)
[stdin]:1 [stdin]:1

Loading…
Cancel
Save