Improve performance of event and timer interfaces
This pull request speeds up multi-listener event callbacks, setImmediate
, setTimeout
, and setInterval
by differentiating between zero-, one-, and two-argument callbacks. This technique was previously only applied to single-listener event callbacks—and even they have been sped up.
Current situation
The EventEmitter#emit
code has special cases for zero-, one-, and two-argument callbacks as follows:
len = arguments.length;
switch (len) {
// fast cases
case 1: handler.call(this); break;
case 2: handler.call(this, arguments[1]); break;
case 3: handler.call(this, arguments[1], arguments[2]); break;
// slower
default:
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
handler.apply(this, args);
}
Improvements in this pull request
On the one hand, this pull request speeds up this technique by avoiding the use of arguments
indexing, instead adding actual function arguments arg1
and arg2
.
On the other hand, this pull request also applies the same technique to listeners with multiple callbacks, as well as the timer functions setImmediate
, setTimeout
, and setInterval
.
Below are my results of performance tests that examine these cases (ran on a 2010 MacBook Pro).
a7f53096 | ← diff → | 17701f939db247233e574bb1ff07191f8c00c877 | |
---|---|---|---|
event with one listener | 631 ms | -24.25% | 478 ms |
event with two listeners | 2,899 ms | -44.98% | 1,595 ms |
setImmediate | 6,758 ms | -40.17% | 4,043 ms |
setTimeout | 8,828 ms | -65.17% | 3,075 ms |
setInterval | 8,830 ms | -71.77% | 2,493 ms |
Considerations
Given the importance of callbacks in io.js, delivering maximum performance for common cases is crucial. The only drawback of this pull request seems to be the increased code length; but it brings consistency since the optimization technique was previously only applied to one particular case (and slightly suboptimally).
I added each change in a different commit, so you can decide which ones to merge. All commits are independent of each other, except for the second, which depends on the first.
If you want these commits squashed, or applied to a different branch, please let me know and I'll do so.
PS This pull request is the equivalent of joyent/node#9007.