mirror of https://github.com/nodejs/node.git
process: slightly simplify next tick execution
Get rid of separate function to call callback from _tickCallback as it no longer yields worthwhile performance improvement. Move some code from nextTick & internalNextTick into TickObject constructor to minimize duplication. PR-URL: https://github.com/nodejs/node/pull/16888 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Timothy Gu <timothygu99@gmail.com>pull/16888/merge
parent
1f5ee33dcb
commit
cbaf59c5b9
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
const common = require('../common.js');
|
const common = require('../common.js');
|
||||||
const bench = common.createBenchmark(main, {
|
const bench = common.createBenchmark(main, {
|
||||||
millions: [2]
|
millions: [4]
|
||||||
});
|
});
|
||||||
|
|
||||||
function main(conf) {
|
function main(conf) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
const common = require('../common.js');
|
const common = require('../common.js');
|
||||||
const bench = common.createBenchmark(main, {
|
const bench = common.createBenchmark(main, {
|
||||||
millions: [2]
|
millions: [4]
|
||||||
});
|
});
|
||||||
|
|
||||||
function main(conf) {
|
function main(conf) {
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
'use strict';
|
||||||
|
const common = require('../common.js');
|
||||||
|
const bench = common.createBenchmark(main, {
|
||||||
|
millions: [5]
|
||||||
|
});
|
||||||
|
|
||||||
|
function main(conf) {
|
||||||
|
var n = +conf.millions * 1e6;
|
||||||
|
|
||||||
|
bench.start();
|
||||||
|
for (var i = 0; i < n; i++) {
|
||||||
|
if (i % 4 === 0)
|
||||||
|
process.nextTick(onNextTick, i, true, 10, 'test');
|
||||||
|
else if (i % 3 === 0)
|
||||||
|
process.nextTick(onNextTick, i, true, 10);
|
||||||
|
else if (i % 2 === 0)
|
||||||
|
process.nextTick(onNextTick, i, 20);
|
||||||
|
else
|
||||||
|
process.nextTick(onNextTick, i);
|
||||||
|
}
|
||||||
|
function onNextTick(i) {
|
||||||
|
if (i + 1 === n)
|
||||||
|
bench.end(+conf.millions);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
'use strict';
|
||||||
|
const common = require('../common.js');
|
||||||
|
const bench = common.createBenchmark(main, {
|
||||||
|
millions: [5]
|
||||||
|
});
|
||||||
|
|
||||||
|
function main(conf) {
|
||||||
|
var n = +conf.millions * 1e6;
|
||||||
|
|
||||||
|
bench.start();
|
||||||
|
for (var i = 0; i < n; i++) {
|
||||||
|
process.nextTick(onNextTick, i);
|
||||||
|
}
|
||||||
|
function onNextTick(i) {
|
||||||
|
if (i + 1 === n)
|
||||||
|
bench.end(+conf.millions);
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,7 +60,7 @@ function setupNextTick() {
|
||||||
// Grab the constants necessary for working with internal arrays.
|
// Grab the constants necessary for working with internal arrays.
|
||||||
const { kInit, kDestroy, kAsyncIdCounter } = async_wrap.constants;
|
const { kInit, kDestroy, kAsyncIdCounter } = async_wrap.constants;
|
||||||
const { async_id_symbol, trigger_async_id_symbol } = async_wrap;
|
const { async_id_symbol, trigger_async_id_symbol } = async_wrap;
|
||||||
var nextTickQueue = new NextTickQueue();
|
const nextTickQueue = new NextTickQueue();
|
||||||
var microtasksScheduled = false;
|
var microtasksScheduled = false;
|
||||||
|
|
||||||
// Used to run V8's micro task queue.
|
// Used to run V8's micro task queue.
|
||||||
|
@ -99,7 +99,6 @@ function setupNextTick() {
|
||||||
const microTasksTickObject = {
|
const microTasksTickObject = {
|
||||||
callback: runMicrotasksCallback,
|
callback: runMicrotasksCallback,
|
||||||
args: undefined,
|
args: undefined,
|
||||||
domain: null,
|
|
||||||
[async_id_symbol]: 0,
|
[async_id_symbol]: 0,
|
||||||
[trigger_async_id_symbol]: 0
|
[trigger_async_id_symbol]: 0
|
||||||
};
|
};
|
||||||
|
@ -125,26 +124,6 @@ function setupNextTick() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(...args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run callbacks that have no domain.
|
// Run callbacks that have no domain.
|
||||||
// Using domains will cause this to be overridden.
|
// Using domains will cause this to be overridden.
|
||||||
function _tickCallback() {
|
function _tickCallback() {
|
||||||
|
@ -152,8 +131,6 @@ function setupNextTick() {
|
||||||
while (tickInfo[kIndex] < tickInfo[kLength]) {
|
while (tickInfo[kIndex] < tickInfo[kLength]) {
|
||||||
++tickInfo[kIndex];
|
++tickInfo[kIndex];
|
||||||
const tock = nextTickQueue.shift();
|
const tock = nextTickQueue.shift();
|
||||||
const callback = tock.callback;
|
|
||||||
const args = tock.args;
|
|
||||||
|
|
||||||
// CHECK(Number.isSafeInteger(tock[async_id_symbol]))
|
// CHECK(Number.isSafeInteger(tock[async_id_symbol]))
|
||||||
// CHECK(tock[async_id_symbol] > 0)
|
// CHECK(tock[async_id_symbol] > 0)
|
||||||
|
@ -173,10 +150,11 @@ function setupNextTick() {
|
||||||
if (async_hook_fields[kDestroy] > 0)
|
if (async_hook_fields[kDestroy] > 0)
|
||||||
emitDestroy(tock[async_id_symbol]);
|
emitDestroy(tock[async_id_symbol]);
|
||||||
|
|
||||||
// Using separate callback execution functions allows direct
|
const callback = tock.callback;
|
||||||
// callback invocation with small numbers of arguments to avoid the
|
if (tock.args === undefined)
|
||||||
// performance hit associated with using `fn.apply()`
|
callback();
|
||||||
_combinedTickCallback(args, callback);
|
else
|
||||||
|
Reflect.apply(callback, undefined, tock.args);
|
||||||
|
|
||||||
emitAfter(tock[async_id_symbol]);
|
emitAfter(tock[async_id_symbol]);
|
||||||
|
|
||||||
|
@ -191,11 +169,21 @@ function setupNextTick() {
|
||||||
|
|
||||||
class TickObject {
|
class TickObject {
|
||||||
constructor(callback, args, asyncId, triggerAsyncId) {
|
constructor(callback, args, asyncId, triggerAsyncId) {
|
||||||
|
// this must be set to null first to avoid function tracking
|
||||||
|
// on the hidden class, revisit in V8 versions after 6.2
|
||||||
|
this.callback = null;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
this.domain = process.domain || null;
|
|
||||||
this[async_id_symbol] = asyncId;
|
this[async_id_symbol] = asyncId;
|
||||||
this[trigger_async_id_symbol] = triggerAsyncId;
|
this[trigger_async_id_symbol] = triggerAsyncId;
|
||||||
|
|
||||||
|
if (async_hook_fields[kInit] > 0) {
|
||||||
|
emitInit(asyncId,
|
||||||
|
'TickObject',
|
||||||
|
triggerAsyncId,
|
||||||
|
this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,13 +208,14 @@ function setupNextTick() {
|
||||||
args[i - 1] = arguments[i];
|
args[i - 1] = arguments[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
const asyncId = ++async_id_fields[kAsyncIdCounter];
|
// In V8 6.2, moving tickInfo & async_id_fields[kAsyncIdCounter] into the
|
||||||
const triggerAsyncId = initTriggerId();
|
// TickObject incurs a significant performance penalty in the
|
||||||
const obj = new TickObject(callback, args, asyncId, triggerAsyncId);
|
// next-tick-breadth-args benchmark (revisit later)
|
||||||
nextTickQueue.push(obj);
|
|
||||||
++tickInfo[kLength];
|
++tickInfo[kLength];
|
||||||
if (async_hook_fields[kInit] > 0)
|
nextTickQueue.push(new TickObject(callback,
|
||||||
emitInit(asyncId, 'TickObject', triggerAsyncId, obj);
|
args,
|
||||||
|
++async_id_fields[kAsyncIdCounter],
|
||||||
|
initTriggerId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// `internalNextTick()` will not enqueue any callback when the process is
|
// `internalNextTick()` will not enqueue any callback when the process is
|
||||||
|
@ -240,10 +229,6 @@ function setupNextTick() {
|
||||||
if (process._exiting)
|
if (process._exiting)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (triggerAsyncId === null) {
|
|
||||||
triggerAsyncId = async_hooks.initTriggerId();
|
|
||||||
}
|
|
||||||
|
|
||||||
var args;
|
var args;
|
||||||
switch (arguments.length) {
|
switch (arguments.length) {
|
||||||
case 2: break;
|
case 2: break;
|
||||||
|
@ -256,11 +241,15 @@ function setupNextTick() {
|
||||||
args[i - 2] = arguments[i];
|
args[i - 2] = arguments[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
const asyncId = ++async_id_fields[kAsyncIdCounter];
|
if (triggerAsyncId === null)
|
||||||
const obj = new TickObject(callback, args, asyncId, triggerAsyncId);
|
triggerAsyncId = initTriggerId();
|
||||||
nextTickQueue.push(obj);
|
// In V8 6.2, moving tickInfo & async_id_fields[kAsyncIdCounter] into the
|
||||||
|
// TickObject incurs a significant performance penalty in the
|
||||||
|
// next-tick-breadth-args benchmark (revisit later)
|
||||||
++tickInfo[kLength];
|
++tickInfo[kLength];
|
||||||
if (async_hook_fields[kInit] > 0)
|
nextTickQueue.push(new TickObject(callback,
|
||||||
emitInit(asyncId, 'TickObject', triggerAsyncId, obj);
|
args,
|
||||||
|
++async_id_fields[kAsyncIdCounter],
|
||||||
|
triggerAsyncId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
^
|
^
|
||||||
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 _combinedTickCallback (internal/process/next_tick.js:*:*)
|
|
||||||
at process._tickCallback (internal/process/next_tick.js:*:*)
|
at process._tickCallback (internal/process/next_tick.js:*:*)
|
||||||
at Function.Module.runMain (module.js:*:*)
|
at Function.Module.runMain (module.js:*:*)
|
||||||
at startup (bootstrap_node.js:*:*)
|
at startup (bootstrap_node.js:*:*)
|
||||||
|
|
|
@ -11,7 +11,6 @@ SyntaxError: Strict mode code may not include a with statement
|
||||||
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
||||||
at Socket.emit (events.js:*:*)
|
at Socket.emit (events.js:*:*)
|
||||||
at endReadableNT (_stream_readable.js:*:*)
|
at endReadableNT (_stream_readable.js:*:*)
|
||||||
at _combinedTickCallback (internal/process/next_tick.js:*:*)
|
|
||||||
at process._tickCallback (internal/process/next_tick.js:*:*)
|
at process._tickCallback (internal/process/next_tick.js:*:*)
|
||||||
42
|
42
|
||||||
42
|
42
|
||||||
|
@ -29,7 +28,7 @@ Error: hello
|
||||||
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
||||||
at Socket.emit (events.js:*:*)
|
at Socket.emit (events.js:*:*)
|
||||||
at endReadableNT (_stream_readable.js:*:*)
|
at endReadableNT (_stream_readable.js:*:*)
|
||||||
at _combinedTickCallback (internal/process/next_tick.js:*:*)
|
at process._tickCallback (internal/process/next_tick.js:*:*)
|
||||||
[stdin]:1
|
[stdin]:1
|
||||||
throw new Error("hello")
|
throw new Error("hello")
|
||||||
^
|
^
|
||||||
|
@ -44,7 +43,7 @@ Error: hello
|
||||||
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
||||||
at Socket.emit (events.js:*:*)
|
at Socket.emit (events.js:*:*)
|
||||||
at endReadableNT (_stream_readable.js:*:*)
|
at endReadableNT (_stream_readable.js:*:*)
|
||||||
at _combinedTickCallback (internal/process/next_tick.js:*:*)
|
at process._tickCallback (internal/process/next_tick.js:*:*)
|
||||||
100
|
100
|
||||||
[stdin]:1
|
[stdin]:1
|
||||||
var x = 100; y = x;
|
var x = 100; y = x;
|
||||||
|
@ -60,7 +59,7 @@ ReferenceError: y is not defined
|
||||||
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
||||||
at Socket.emit (events.js:*:*)
|
at Socket.emit (events.js:*:*)
|
||||||
at endReadableNT (_stream_readable.js:*:*)
|
at endReadableNT (_stream_readable.js:*:*)
|
||||||
at _combinedTickCallback (internal/process/next_tick.js:*:*)
|
at process._tickCallback (internal/process/next_tick.js:*:*)
|
||||||
|
|
||||||
[stdin]:1
|
[stdin]:1
|
||||||
var ______________________________________________; throw 10
|
var ______________________________________________; throw 10
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
at *
|
at *
|
||||||
at *
|
at *
|
||||||
at *
|
at *
|
||||||
at *
|
|
||||||
(node:*) Error: This was rejected
|
(node:*) Error: This was rejected
|
||||||
at * (*test*message*unhandled_promise_trace_warnings.js:*)
|
at * (*test*message*unhandled_promise_trace_warnings.js:*)
|
||||||
at *
|
at *
|
||||||
|
@ -34,7 +33,6 @@
|
||||||
at *
|
at *
|
||||||
at *
|
at *
|
||||||
at *
|
at *
|
||||||
at *
|
|
||||||
(node:*) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
|
(node:*) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
|
||||||
at getAsynchronousRejectionWarningObject (internal/process/promises.js:*)
|
at getAsynchronousRejectionWarningObject (internal/process/promises.js:*)
|
||||||
at rejectionHandled (internal/process/promises.js:*)
|
at rejectionHandled (internal/process/promises.js:*)
|
||||||
|
|
Loading…
Reference in New Issue