events: improve arrayClone performance

PR-URL: https://github.com/nodejs/node/pull/33774
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Zeyu Yang <himself65@outlook.com>
This commit is contained in:
Brian White 2020-06-06 14:18:46 -04:00
parent 651088c3e6
commit 4ba90809ed
No known key found for this signature in database
GPG Key ID: 606D7358F94DA209
4 changed files with 36 additions and 37 deletions

View File

@ -10,6 +10,7 @@ const bench = common.createBenchmark(main, {
function main({ n, argc, listeners }) {
const ee = new EventEmitter();
ee.setMaxListeners(listeners + 1);
for (let k = 0; k < listeners; k += 1)
ee.on('dummy', () => {});

View File

@ -1,22 +0,0 @@
'use strict';
const common = require('../common.js');
const EventEmitter = require('events').EventEmitter;
const bench = common.createBenchmark(main, { n: [5e6] });
function main({ n }) {
const ee = new EventEmitter();
ee.setMaxListeners(101);
for (let k = 0; k < 50; k += 1) {
ee.on('dummy0', () => {});
ee.on('dummy1', () => {});
}
bench.start();
for (let i = 0; i < n; i += 1) {
const dummy = (i % 2 === 0) ? 'dummy0' : 'dummy1';
ee.listeners(dummy);
}
bench.end(n);
}

View File

@ -2,20 +2,34 @@
const common = require('../common.js');
const EventEmitter = require('events').EventEmitter;
const bench = common.createBenchmark(main, { n: [5e6] });
const bench = common.createBenchmark(main, {
n: [5e6],
listeners: [5, 50],
raw: ['true', 'false']
});
function main({ n }) {
function main({ n, listeners, raw }) {
const ee = new EventEmitter();
ee.setMaxListeners(listeners * 2 + 1);
for (let k = 0; k < 5; k += 1) {
for (let k = 0; k < listeners; k += 1) {
ee.on('dummy0', () => {});
ee.on('dummy1', () => {});
}
bench.start();
for (let i = 0; i < n; i += 1) {
const dummy = (i % 2 === 0) ? 'dummy0' : 'dummy1';
ee.listeners(dummy);
if (raw === 'true') {
bench.start();
for (let i = 0; i < n; i += 1) {
const dummy = (i % 2 === 0) ? 'dummy0' : 'dummy1';
ee.rawListeners(dummy);
}
bench.end(n);
} else {
bench.start();
for (let i = 0; i < n; i += 1) {
const dummy = (i % 2 === 0) ? 'dummy0' : 'dummy1';
ee.listeners(dummy);
}
bench.end(n);
}
bench.end(n);
}

View File

@ -322,7 +322,7 @@ EventEmitter.prototype.emit = function emit(type, ...args) {
}
} else {
const len = handler.length;
const listeners = arrayClone(handler, len);
const listeners = arrayClone(handler);
for (let i = 0; i < len; ++i) {
const result = ReflectApply(listeners[i], this, args);
@ -560,7 +560,7 @@ function _listeners(target, type, unwrap) {
return unwrap ? [evlistener.listener || evlistener] : [evlistener];
return unwrap ?
unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
unwrapListeners(evlistener) : arrayClone(evlistener);
}
EventEmitter.prototype.listeners = function listeners(type) {
@ -599,11 +599,17 @@ EventEmitter.prototype.eventNames = function eventNames() {
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
};
function arrayClone(arr, n) {
const copy = new Array(n);
for (let i = 0; i < n; ++i)
copy[i] = arr[i];
return copy;
function arrayClone(arr) {
// At least since V8 8.3, this implementation is faster than the previous
// which always used a simple for-loop
switch (arr.length) {
case 2: return [arr[0], arr[1]];
case 3: return [arr[0], arr[1], arr[2]];
case 4: return [arr[0], arr[1], arr[2], arr[3]];
case 5: return [arr[0], arr[1], arr[2], arr[3], arr[4]];
case 6: return [arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]];
}
return arr.slice();
}
function unwrapListeners(arr) {