Skip to content

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.

Merge request reports

Loading