From 830574f19909502242b2bb1d14f553d06f72a265 Mon Sep 17 00:00:00 2001 From: Brian White Date: Sat, 6 Jun 2020 14:18:46 -0400 Subject: [PATCH] events: improve arrayClone performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/33774 Reviewed-By: Robert Nagy Reviewed-By: James M Snell Reviewed-By: Benjamin Gruenbaum Reviewed-By: Michaƫl Zasso Reviewed-By: Zeyu Yang --- benchmark/events/ee-emit.js | 1 + benchmark/events/ee-listeners-many.js | 22 -------------------- benchmark/events/ee-listeners.js | 30 ++++++++++++++++++++------- lib/events.js | 20 +++++++++++------- 4 files changed, 36 insertions(+), 37 deletions(-) delete mode 100644 benchmark/events/ee-listeners-many.js diff --git a/benchmark/events/ee-emit.js b/benchmark/events/ee-emit.js index 39bcbb937d6c56..ec35277a9c0214 100644 --- a/benchmark/events/ee-emit.js +++ b/benchmark/events/ee-emit.js @@ -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', () => {}); diff --git a/benchmark/events/ee-listeners-many.js b/benchmark/events/ee-listeners-many.js deleted file mode 100644 index bd3f3538d63c92..00000000000000 --- a/benchmark/events/ee-listeners-many.js +++ /dev/null @@ -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); -} diff --git a/benchmark/events/ee-listeners.js b/benchmark/events/ee-listeners.js index 867393efffcb04..08631e95e2165a 100644 --- a/benchmark/events/ee-listeners.js +++ b/benchmark/events/ee-listeners.js @@ -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); } diff --git a/lib/events.js b/lib/events.js index fc2f969ea37ef6..6717363acbff96 100644 --- a/lib/events.js +++ b/lib/events.js @@ -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); @@ -563,7 +563,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) { @@ -602,11 +602,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) {