timers: improve setImmediate() performance
This commit improves setImmediate() performance by moving the try-finally block that wraps callback execution into a separate function because currently v8 never tries to optimize functions that contain try-finally blocks. With this change, there is a ~20-40% improvement in the included setImmediate() depth benchmarks. The breadth benchmarks show a slight improvement. PR-URL: https://github.com/nodejs/node/pull/4169 Reviewed-By: Minwoo Jung <jmwsoft@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
This commit is contained in:
parent
ad8257fa5b
commit
089bef0a81
28
benchmark/misc/set-immediate-breadth-args.js
Normal file
28
benchmark/misc/set-immediate-breadth-args.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common.js');
|
||||||
|
const bench = common.createBenchmark(main, {
|
||||||
|
millions: [5]
|
||||||
|
});
|
||||||
|
|
||||||
|
function main(conf) {
|
||||||
|
const N = +conf.millions * 1e6;
|
||||||
|
|
||||||
|
process.on('exit', function() {
|
||||||
|
bench.end(N / 1e6);
|
||||||
|
});
|
||||||
|
|
||||||
|
function cb1(arg1) {}
|
||||||
|
function cb2(arg1, arg2) {}
|
||||||
|
function cb3(arg1, arg2, arg3) {}
|
||||||
|
|
||||||
|
bench.start();
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
if (i % 3 === 0)
|
||||||
|
setImmediate(cb3, 512, true, null);
|
||||||
|
else if (i % 2 === 0)
|
||||||
|
setImmediate(cb2, false, 5.1);
|
||||||
|
else
|
||||||
|
setImmediate(cb1, 0);
|
||||||
|
}
|
||||||
|
}
|
21
benchmark/misc/set-immediate-breadth.js
Normal file
21
benchmark/misc/set-immediate-breadth.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common.js');
|
||||||
|
const bench = common.createBenchmark(main, {
|
||||||
|
millions: [10]
|
||||||
|
});
|
||||||
|
|
||||||
|
function main(conf) {
|
||||||
|
const N = +conf.millions * 1e6;
|
||||||
|
|
||||||
|
process.on('exit', function() {
|
||||||
|
bench.end(N / 1e6);
|
||||||
|
});
|
||||||
|
|
||||||
|
function cb() {}
|
||||||
|
|
||||||
|
bench.start();
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
setImmediate(cb);
|
||||||
|
}
|
||||||
|
}
|
47
benchmark/misc/set-immediate-depth-args.js
Normal file
47
benchmark/misc/set-immediate-depth-args.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common.js');
|
||||||
|
const bench = common.createBenchmark(main, {
|
||||||
|
millions: [10]
|
||||||
|
});
|
||||||
|
|
||||||
|
function main(conf) {
|
||||||
|
const N = +conf.millions * 1e6;
|
||||||
|
|
||||||
|
process.on('exit', function() {
|
||||||
|
bench.end(N / 1e6);
|
||||||
|
});
|
||||||
|
|
||||||
|
function cb3(n, arg2, arg3) {
|
||||||
|
if (--n) {
|
||||||
|
if (n % 3 === 0)
|
||||||
|
setImmediate(cb3, n, true, null);
|
||||||
|
else if (n % 2 === 0)
|
||||||
|
setImmediate(cb2, n, 5.1);
|
||||||
|
else
|
||||||
|
setImmediate(cb1, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function cb2(n, arg2) {
|
||||||
|
if (--n) {
|
||||||
|
if (n % 3 === 0)
|
||||||
|
setImmediate(cb3, n, true, null);
|
||||||
|
else if (n % 2 === 0)
|
||||||
|
setImmediate(cb2, n, 5.1);
|
||||||
|
else
|
||||||
|
setImmediate(cb1, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function cb1(n) {
|
||||||
|
if (--n) {
|
||||||
|
if (n % 3 === 0)
|
||||||
|
setImmediate(cb3, n, true, null);
|
||||||
|
else if (n % 2 === 0)
|
||||||
|
setImmediate(cb2, n, 5.1);
|
||||||
|
else
|
||||||
|
setImmediate(cb1, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bench.start();
|
||||||
|
setImmediate(cb1, N);
|
||||||
|
}
|
22
benchmark/misc/set-immediate-depth.js
Normal file
22
benchmark/misc/set-immediate-depth.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common.js');
|
||||||
|
const bench = common.createBenchmark(main, {
|
||||||
|
millions: [10]
|
||||||
|
});
|
||||||
|
|
||||||
|
function main(conf) {
|
||||||
|
const N = +conf.millions * 1e6;
|
||||||
|
let n = N;
|
||||||
|
|
||||||
|
process.on('exit', function() {
|
||||||
|
bench.end(N / 1e6);
|
||||||
|
});
|
||||||
|
|
||||||
|
bench.start();
|
||||||
|
setImmediate(onNextTick);
|
||||||
|
function onNextTick() {
|
||||||
|
if (--n)
|
||||||
|
setImmediate(onNextTick);
|
||||||
|
}
|
||||||
|
}
|
@ -215,8 +215,8 @@ function listOnTimeout() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// An optimization so that the try/finally only de-optimizes what is in this
|
// An optimization so that the try/finally only de-optimizes (since at least v8
|
||||||
// smaller function.
|
// 4.7) what is in this smaller function.
|
||||||
function tryOnTimeout(timer, list) {
|
function tryOnTimeout(timer, list) {
|
||||||
timer._called = true;
|
timer._called = true;
|
||||||
var threw = true;
|
var threw = true;
|
||||||
@ -520,23 +520,7 @@ function processImmediate() {
|
|||||||
if (domain)
|
if (domain)
|
||||||
domain.enter();
|
domain.enter();
|
||||||
|
|
||||||
var threw = true;
|
tryOnImmediate(immediate, queue);
|
||||||
try {
|
|
||||||
immediate._onImmediate();
|
|
||||||
threw = false;
|
|
||||||
} finally {
|
|
||||||
if (threw) {
|
|
||||||
if (!L.isEmpty(queue)) {
|
|
||||||
// Handle any remaining on next tick, assuming we're still
|
|
||||||
// alive to do so.
|
|
||||||
while (!L.isEmpty(immediateQueue)) {
|
|
||||||
L.append(queue, L.shift(immediateQueue));
|
|
||||||
}
|
|
||||||
immediateQueue = queue;
|
|
||||||
process.nextTick(processImmediate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (domain)
|
if (domain)
|
||||||
domain.exit();
|
domain.exit();
|
||||||
@ -551,6 +535,26 @@ function processImmediate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// An optimization so that the try/finally only de-optimizes (since at least v8
|
||||||
|
// 4.7) what is in this smaller function.
|
||||||
|
function tryOnImmediate(immediate, queue) {
|
||||||
|
var threw = true;
|
||||||
|
try {
|
||||||
|
immediate._onImmediate();
|
||||||
|
threw = false;
|
||||||
|
} finally {
|
||||||
|
if (threw && !L.isEmpty(queue)) {
|
||||||
|
// Handle any remaining on next tick, assuming we're still alive to do so.
|
||||||
|
while (!L.isEmpty(immediateQueue)) {
|
||||||
|
L.append(queue, L.shift(immediateQueue));
|
||||||
|
}
|
||||||
|
immediateQueue = queue;
|
||||||
|
process.nextTick(processImmediate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function Immediate() { }
|
function Immediate() { }
|
||||||
|
|
||||||
Immediate.prototype.domain = undefined;
|
Immediate.prototype.domain = undefined;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user