From dc6403eb2141779ff261d8c693ffead09730df1a Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 4 Feb 2016 22:36:48 +0100 Subject: [PATCH 1/2] 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. --- src/node.js | 117 +++++++------------------------- test/message/eval_messages.out | 8 +-- test/message/nexttick_throw.out | 2 +- test/message/stdin_messages.out | 8 +-- 4 files changed, 33 insertions(+), 102 deletions(-) diff --git a/src/node.js b/src/node.js index 2856943e4a9e78..45b7e6252d5464 100644 --- a/src/node.js +++ b/src/node.js @@ -373,6 +373,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() { @@ -383,27 +403,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(); } @@ -424,27 +427,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) @@ -456,61 +442,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; diff --git a/test/message/eval_messages.out b/test/message/eval_messages.out index 4fb3c7f56d5859..c299ec3ae1345c 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 1e03f6de84b90a..72f04b00936977 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 57908426079e15..2e08a70cc46fbc 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 From 16ad4b761b0dd148582e580fa88b6241f61526cd Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 4 Feb 2016 22:50:21 +0100 Subject: [PATCH 2/2] node: improve process.nextTick performance Using a predefined array size prevents resizing the array and is therefor faster. --- src/node.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node.js b/src/node.js index 45b7e6252d5464..655b0d4633d85e 100644 --- a/src/node.js +++ b/src/node.js @@ -457,9 +457,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));