From 88307974e60346bc98c4e9f70a2b6918ccb6844f Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 4 Feb 2016 22:36:48 +0100 Subject: [PATCH] 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 Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell --- src/node.js | 121 +++++++------------------------- test/message/eval_messages.out | 8 +-- test/message/nexttick_throw.out | 2 +- test/message/stdin_messages.out | 8 +-- 4 files changed, 35 insertions(+), 104 deletions(-) diff --git a/src/node.js b/src/node.js index cdb147d4f9..40ae7cacff 100644 --- a/src/node.js +++ b/src/node.js @@ -374,6 +374,26 @@ scheduleMicrotasks(); } + function _combinedTickCallback(args, callback) { + if (args === undefined) { + callback(); + } else { + switch (args.length) { + case 1: + callback(args[0]); + break; + case 2: + callback(args[0], args[1]); + break; + case 3: + callback(args[0], args[1], args[2]); + break; + default: + callback.apply(null, args); + } + } + } + // Run callbacks that have no domain. // Using domains will cause this to be overridden. function _tickCallback() { @@ -384,27 +404,10 @@ 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 + // Using separate callback execution functions allows direct // callback invocation with small numbers of arguments to avoid the // performance hit associated with using `fn.apply()` - if (args === undefined) { - 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); - } - } + _combinedTickCallback(args, callback); if (1e4 < tickInfo[kIndex]) tickDone(); } @@ -425,27 +428,10 @@ args = tock.args; if (domain) domain.enter(); - // Using separate callback execution functions helps to limit the - // scope of DEOPTs caused by using try blocks and allows direct + // Using separate callback execution functions allows direct // callback invocation with small numbers of arguments to avoid the // performance hit associated with using `fn.apply()` - if (args === undefined) { - 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); - } - } + _combinedTickCallback(args, callback); if (1e4 < tickInfo[kIndex]) tickDone(); if (domain) @@ -457,61 +443,6 @@ } 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) { this.callback = c; this.domain = process.domain || null; @@ -527,9 +458,9 @@ var args; if (arguments.length > 1) { - args = []; + args = new Array(arguments.length - 1); for (var i = 1; i < arguments.length; i++) - args.push(arguments[i]); + args[i - 1] = arguments[i]; } nextTickQueue.push(new TickObject(callback, args)); diff --git a/test/message/eval_messages.out b/test/message/eval_messages.out index 4fb3c7f56d..c299ec3ae1 100644 --- a/test/message/eval_messages.out +++ b/test/message/eval_messages.out @@ -7,7 +7,7 @@ SyntaxError: Strict mode code may not include a with statement at Object. ([eval]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at nextTickCallbackWith0Args (node.js:*:*) + at _combinedTickCallback (node.js:*:*) at process._tickCallback (node.js:*:*) 42 42 @@ -20,7 +20,7 @@ Error: hello at Object. ([eval]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at nextTickCallbackWith0Args (node.js:*:*) + at _combinedTickCallback (node.js:*:*) at process._tickCallback (node.js:*:*) [eval]:1 throw new Error("hello") @@ -31,7 +31,7 @@ Error: hello at Object. ([eval]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at nextTickCallbackWith0Args (node.js:*:*) + at _combinedTickCallback (node.js:*:*) at process._tickCallback (node.js:*:*) 100 [eval]:1 @@ -43,7 +43,7 @@ ReferenceError: y is not defined at Object. ([eval]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at nextTickCallbackWith0Args (node.js:*:*) + at _combinedTickCallback (node.js:*:*) at process._tickCallback (node.js:*:*) [eval]:1 var ______________________________________________; throw 10 diff --git a/test/message/nexttick_throw.out b/test/message/nexttick_throw.out index 1e03f6de84..72f04b0093 100644 --- a/test/message/nexttick_throw.out +++ b/test/message/nexttick_throw.out @@ -4,7 +4,7 @@ ^ ReferenceError: undefined_reference_error_maker is not defined at *test*message*nexttick_throw.js:*:* - at nextTickCallbackWith0Args (node.js:*:*) + at _combinedTickCallback (node.js:*:*) at process._tickCallback (node.js:*:*) at Function.Module.runMain (module.js:*:*) at startup (node.js:*:*) diff --git a/test/message/stdin_messages.out b/test/message/stdin_messages.out index 5790842607..2e08a70cc4 100644 --- a/test/message/stdin_messages.out +++ b/test/message/stdin_messages.out @@ -8,7 +8,7 @@ SyntaxError: Strict mode code may not include a with statement at Object. ([stdin]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at nextTickCallbackWith0Args (node.js:*:*) + at _combinedTickCallback (node.js:*:*) at process._tickCallback (node.js:*:*) 42 42 @@ -22,7 +22,7 @@ Error: hello at Object. ([stdin]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at nextTickCallbackWith0Args (node.js:*:*) + at _combinedTickCallback (node.js:*:*) at process._tickCallback (node.js:*:*) [stdin]:1 @@ -34,7 +34,7 @@ Error: hello at Object. ([stdin]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at nextTickCallbackWith0Args (node.js:*:*) + at _combinedTickCallback (node.js:*:*) at process._tickCallback (node.js:*:*) 100 @@ -47,7 +47,7 @@ ReferenceError: y is not defined at Object. ([stdin]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at nextTickCallbackWith0Args (node.js:*:*) + at _combinedTickCallback (node.js:*:*) at process._tickCallback (node.js:*:*) [stdin]:1