Skip to content

Commit d3654d8

Browse files
mscdexFishrock123
authored andcommitted
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: #4169 Reviewed-By: Minwoo Jung <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Jeremiah Senkpiel <[email protected]>
1 parent b1a4870 commit d3654d8

File tree

5 files changed

+141
-19
lines changed

5 files changed

+141
-19
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const bench = common.createBenchmark(main, {
5+
millions: [5]
6+
});
7+
8+
function main(conf) {
9+
const N = +conf.millions * 1e6;
10+
11+
process.on('exit', function() {
12+
bench.end(N / 1e6);
13+
});
14+
15+
function cb1(arg1) {}
16+
function cb2(arg1, arg2) {}
17+
function cb3(arg1, arg2, arg3) {}
18+
19+
bench.start();
20+
for (let i = 0; i < N; i++) {
21+
if (i % 3 === 0)
22+
setImmediate(cb3, 512, true, null);
23+
else if (i % 2 === 0)
24+
setImmediate(cb2, false, 5.1);
25+
else
26+
setImmediate(cb1, 0);
27+
}
28+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const bench = common.createBenchmark(main, {
5+
millions: [10]
6+
});
7+
8+
function main(conf) {
9+
const N = +conf.millions * 1e6;
10+
11+
process.on('exit', function() {
12+
bench.end(N / 1e6);
13+
});
14+
15+
function cb() {}
16+
17+
bench.start();
18+
for (let i = 0; i < N; i++) {
19+
setImmediate(cb);
20+
}
21+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const bench = common.createBenchmark(main, {
5+
millions: [10]
6+
});
7+
8+
function main(conf) {
9+
const N = +conf.millions * 1e6;
10+
11+
process.on('exit', function() {
12+
bench.end(N / 1e6);
13+
});
14+
15+
function cb3(n, arg2, arg3) {
16+
if (--n) {
17+
if (n % 3 === 0)
18+
setImmediate(cb3, n, true, null);
19+
else if (n % 2 === 0)
20+
setImmediate(cb2, n, 5.1);
21+
else
22+
setImmediate(cb1, n);
23+
}
24+
}
25+
function cb2(n, arg2) {
26+
if (--n) {
27+
if (n % 3 === 0)
28+
setImmediate(cb3, n, true, null);
29+
else if (n % 2 === 0)
30+
setImmediate(cb2, n, 5.1);
31+
else
32+
setImmediate(cb1, n);
33+
}
34+
}
35+
function cb1(n) {
36+
if (--n) {
37+
if (n % 3 === 0)
38+
setImmediate(cb3, n, true, null);
39+
else if (n % 2 === 0)
40+
setImmediate(cb2, n, 5.1);
41+
else
42+
setImmediate(cb1, n);
43+
}
44+
}
45+
bench.start();
46+
setImmediate(cb1, N);
47+
}

benchmark/misc/set-immediate-depth.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const bench = common.createBenchmark(main, {
5+
millions: [10]
6+
});
7+
8+
function main(conf) {
9+
const N = +conf.millions * 1e6;
10+
let n = N;
11+
12+
process.on('exit', function() {
13+
bench.end(N / 1e6);
14+
});
15+
16+
bench.start();
17+
setImmediate(onNextTick);
18+
function onNextTick() {
19+
if (--n)
20+
setImmediate(onNextTick);
21+
}
22+
}

lib/timers.js

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,8 @@ function listOnTimeout() {
215215
}
216216

217217

218-
// An optimization so that the try/finally only de-optimizes what is in this
219-
// smaller function.
218+
// An optimization so that the try/finally only de-optimizes (since at least v8
219+
// 4.7) what is in this smaller function.
220220
function tryOnTimeout(timer, list) {
221221
timer._called = true;
222222
var threw = true;
@@ -511,23 +511,7 @@ function processImmediate() {
511511
if (domain)
512512
domain.enter();
513513

514-
var threw = true;
515-
try {
516-
immediate._onImmediate();
517-
threw = false;
518-
} finally {
519-
if (threw) {
520-
if (!L.isEmpty(queue)) {
521-
// Handle any remaining on next tick, assuming we're still
522-
// alive to do so.
523-
while (!L.isEmpty(immediateQueue)) {
524-
L.append(queue, L.shift(immediateQueue));
525-
}
526-
immediateQueue = queue;
527-
process.nextTick(processImmediate);
528-
}
529-
}
530-
}
514+
tryOnImmediate(immediate, queue);
531515

532516
if (domain)
533517
domain.exit();
@@ -542,6 +526,26 @@ function processImmediate() {
542526
}
543527

544528

529+
// An optimization so that the try/finally only de-optimizes (since at least v8
530+
// 4.7) what is in this smaller function.
531+
function tryOnImmediate(immediate, queue) {
532+
var threw = true;
533+
try {
534+
immediate._onImmediate();
535+
threw = false;
536+
} finally {
537+
if (threw && !L.isEmpty(queue)) {
538+
// Handle any remaining on next tick, assuming we're still alive to do so.
539+
while (!L.isEmpty(immediateQueue)) {
540+
L.append(queue, L.shift(immediateQueue));
541+
}
542+
immediateQueue = queue;
543+
process.nextTick(processImmediate);
544+
}
545+
}
546+
}
547+
548+
545549
function Immediate() { }
546550

547551
Immediate.prototype.domain = undefined;

0 commit comments

Comments
 (0)