node
node copied to clipboard
events: add fast and slow path
Thank you @benjamingr for the idea
WIP!!!, fixed most of the tests
TODO
- [x] fix a lot of TODOs
- [x] Extract to files
- [ ] Extract files separation to different PR after all test pass and we are happy-ish that we are willing to to merge it https://github.com/nodejs/node/pull/52726 maybe split to multiple commits to keep the history of original events file
- [ ] fix failing tests
- [x] Check
lib/domain.js
as it override emit function - [x] Check streams performance as well to see how it is affected
- [x] Optimize for streams which has
kCapture
enabled - [ ] Fix performance penalty in streams
- [ ] Run CITGM so we can be sure we are not breaking anyone as this is sensitive place
- [ ] fix broken jest https://github.com/jestjs/jest/blob/654dbd6f6b3d94c604221e1afd70fcfb66f9478e/packages/jest-util/src/tests/createProcessObject.test.ts#L20-L40
Benchmarks
events
confidence improvement accuracy (*) (**) (***)
events/ee-add-remove.js n=1000000 removeListener=0 newListener=0 -0.25 % ±0.71% ±0.95% ±1.24%
events/ee-add-remove.js n=1000000 removeListener=0 newListener=1 *** 10.22 % ±0.63% ±0.84% ±1.10%
events/ee-add-remove.js n=1000000 removeListener=1 newListener=0 0.23 % ±0.71% ±0.95% ±1.24%
events/ee-add-remove.js n=1000000 removeListener=1 newListener=1 *** 7.33 % ±0.85% ±1.13% ±1.48%
events/ee-emit.js listeners=1 argc=0 n=2000000 *** 111.60 % ±6.32% ±8.47% ±11.14%
events/ee-emit.js listeners=1 argc=10 n=2000000 *** -21.98 % ±1.40% ±1.86% ±2.42%
events/ee-emit.js listeners=1 argc=2 n=2000000 *** 110.07 % ±4.38% ±5.83% ±7.59%
events/ee-emit.js listeners=1 argc=4 n=2000000 *** 99.87 % ±5.63% ±7.49% ±9.75%
events/ee-emit.js listeners=10 argc=0 n=2000000 *** 7.45 % ±0.80% ±1.08% ±1.42%
events/ee-emit.js listeners=10 argc=10 n=2000000 *** 6.16 % ±0.44% ±0.59% ±0.77%
events/ee-emit.js listeners=10 argc=2 n=2000000 *** 7.60 % ±0.79% ±1.05% ±1.36%
events/ee-emit.js listeners=10 argc=4 n=2000000 *** 7.78 % ±1.17% ±1.57% ±2.07%
events/ee-emit.js listeners=5 argc=0 n=2000000 *** 17.87 % ±1.36% ±1.81% ±2.36%
events/ee-emit.js listeners=5 argc=10 n=2000000 *** 13.65 % ±1.13% ±1.50% ±1.96%
events/ee-emit.js listeners=5 argc=2 n=2000000 *** 7.37 % ±1.26% ±1.69% ±2.22%
events/ee-emit.js listeners=5 argc=4 n=2000000 *** 18.39 % ±1.30% ±1.74% ±2.27%
events/ee-listen-unique.js n=1000000 events=1 0.13 % ±0.47% ±0.63% ±0.82%
events/ee-listen-unique.js n=1000000 events=10 * 1.20 % ±1.12% ±1.49% ±1.94%
events/ee-listen-unique.js n=1000000 events=2 * -0.75 % ±0.71% ±0.94% ±1.23%
events/ee-listen-unique.js n=1000000 events=20 0.35 % ±1.39% ±1.85% ±2.41%
events/ee-listen-unique.js n=1000000 events=3 ** -1.68 % ±1.11% ±1.48% ±1.94%
events/ee-listen-unique.js n=1000000 events=5 0.10 % ±0.96% ±1.28% ±1.67%
events/ee-listener-count-on-prototype.js n=50000000 *** -16.68 % ±1.27% ±1.70% ±2.24%
events/ee-listeners.js raw='false' listeners=5 n=5000000 *** -6.19 % ±0.83% ±1.11% ±1.44%
events/ee-listeners.js raw='false' listeners=50 n=5000000 *** -2.50 % ±0.48% ±0.64% ±0.83%
events/ee-listeners.js raw='true' listeners=5 n=5000000 *** -9.56 % ±0.95% ±1.27% ±1.65%
events/ee-listeners.js raw='true' listeners=50 n=5000000 *** -1.63 % ±0.64% ±0.86% ±1.12%
events/ee-once.js argc=0 n=20000000 *** 17.17 % ±1.12% ±1.49% ±1.96%
events/ee-once.js argc=1 n=20000000 *** 14.88 % ±1.57% ±2.11% ±2.78%
events/ee-once.js argc=4 n=20000000 *** 11.77 % ±0.71% ±0.95% ±1.24%
events/ee-once.js argc=5 n=20000000 *** 12.95 % ±1.20% ±1.60% ±2.08%
Be aware that when doing many comparisons the risk of a false-positive
result increases. In this case, there are 31 comparisons, you can thus
expect the following amount of false-positive results:
1.55 false positives, when considering a 5% risk acceptance (*, **, ***),
0.31 false positives, when considering a 1% risk acceptance (**, ***),
0.03 false positives, when considering a 0.1% risk acceptance (***)
outdated benchmark result
confidence improvement accuracy (*) (**) (***)
events/ee-add-remove.js n=1000000 removeListener=0 newListener=0 *** 1.08 % ±0.57% ±0.76% ±0.99%
events/ee-add-remove.js n=1000000 removeListener=0 newListener=1 *** 11.93 % ±0.69% ±0.92% ±1.20%
events/ee-add-remove.js n=1000000 removeListener=1 newListener=0 ** 1.10 % ±0.75% ±0.99% ±1.29%
events/ee-add-remove.js n=1000000 removeListener=1 newListener=1 *** 7.78 % ±0.71% ±0.95% ±1.24%
events/ee-emit.js listeners=1 argc=0 n=2000000 *** 110.02 % ±2.90% ±3.86% ±5.03%
events/ee-emit.js listeners=1 argc=10 n=2000000 *** -21.73 % ±3.21% ±4.28% ±5.57%
events/ee-emit.js listeners=1 argc=2 n=2000000 *** 102.72 % ±5.43% ±7.24% ±9.48%
events/ee-emit.js listeners=1 argc=4 n=2000000 *** 98.91 % ±6.48% ±8.66% ±11.35%
events/ee-emit.js listeners=10 argc=0 n=2000000 *** 8.77 % ±0.73% ±0.97% ±1.26%
events/ee-emit.js listeners=10 argc=10 n=2000000 *** 6.19 % ±0.39% ±0.52% ±0.68%
events/ee-emit.js listeners=10 argc=2 n=2000000 *** 6.92 % ±0.88% ±1.17% ±1.54%
events/ee-emit.js listeners=10 argc=4 n=2000000 *** 6.71 % ±0.76% ±1.01% ±1.32%
events/ee-emit.js listeners=5 argc=0 n=2000000 *** 17.82 % ±0.90% ±1.20% ±1.56%
events/ee-emit.js listeners=5 argc=10 n=2000000 *** 14.79 % ±0.75% ±0.99% ±1.29%
events/ee-emit.js listeners=5 argc=2 n=2000000 *** 7.11 % ±0.94% ±1.25% ±1.63%
events/ee-emit.js listeners=5 argc=4 n=2000000 *** 17.21 % ±1.11% ±1.48% ±1.94%
events/ee-listen-unique.js n=1000000 events=1 0.27 % ±0.53% ±0.70% ±0.91%
events/ee-listen-unique.js n=1000000 events=10 ** 1.72 % ±1.06% ±1.41% ±1.83%
events/ee-listen-unique.js n=1000000 events=2 0.05 % ±0.82% ±1.09% ±1.41%
events/ee-listen-unique.js n=1000000 events=20 0.96 % ±1.36% ±1.81% ±2.36%
events/ee-listen-unique.js n=1000000 events=3 ** 1.51 % ±1.10% ±1.46% ±1.90%
events/ee-listen-unique.js n=1000000 events=5 ** 1.65 % ±0.98% ±1.31% ±1.70%
events/ee-listener-count-on-prototype.js n=50000000 *** -16.19 % ±1.44% ±1.93% ±2.54%
events/ee-listeners.js raw='false' listeners=5 n=5000000 *** -5.07 % ±0.57% ±0.76% ±0.99%
events/ee-listeners.js raw='false' listeners=50 n=5000000 *** -1.68 % ±0.46% ±0.61% ±0.79%
events/ee-listeners.js raw='true' listeners=5 n=5000000 *** -10.91 % ±1.03% ±1.37% ±1.78%
events/ee-listeners.js raw='true' listeners=50 n=5000000 ** 0.93 % ±0.61% ±0.81% ±1.06%
events/ee-once.js argc=0 n=20000000 *** 15.84 % ±1.81% ±2.41% ±3.14%
events/ee-once.js argc=1 n=20000000 *** 13.77 % ±1.16% ±1.56% ±2.07%
events/ee-once.js argc=4 n=20000000 *** 11.74 % ±0.63% ±0.84% ±1.09%
events/ee-once.js argc=5 n=20000000 *** 13.90 % ±1.14% ±1.53% ±2.01%
Be aware that when doing many comparisons the risk of a false-positive
result increases. In this case, there are 31 comparisons, you can thus
expect the following amount of false-positive results:
1.55 false positives, when considering a 5% risk acceptance (*, **, ***),
0.31 false positives, when considering a 1% risk acceptance (**, ***),
0.03 false positives, when considering a 0.1% risk acceptance (***)
streams
confidence improvement accuracy (*) (**) (***)
streams/creation.js kind='duplex' n=50000000 *** -12.91 % ±0.56% ±0.75% ±0.99%
streams/creation.js kind='readable' n=50000000 *** -34.50 % ±0.61% ±0.81% ±1.06%
streams/creation.js kind='transform' n=50000000 *** -11.56 % ±2.02% ±2.69% ±3.50%
streams/creation.js kind='writable' n=50000000 *** -19.04 % ±0.77% ±1.02% ±1.33%
streams/destroy.js kind='duplex' n=1000000 *** -12.93 % ±0.39% ±0.52% ±0.68%
streams/destroy.js kind='readable' n=1000000 *** -26.69 % ±2.16% ±2.90% ±3.84%
streams/destroy.js kind='transform' n=1000000 *** -16.18 % ±0.49% ±0.65% ±0.84%
streams/destroy.js kind='writable' n=1000000 *** -18.73 % ±0.90% ±1.20% ±1.57%
streams/pipe-object-mode.js n=5000000 *** 5.55 % ±0.37% ±0.50% ±0.65%
streams/pipe.js n=5000000 *** 2.28 % ±0.35% ±0.46% ±0.60%
streams/readable-async-iterator.js sync='no' n=100000 -1.17 % ±1.29% ±1.71% ±2.24%
streams/readable-async-iterator.js sync='yes' n=100000 *** -3.41 % ±1.63% ±2.16% ±2.82%
streams/readable-bigread.js n=1000 *** -1.68 % ±0.67% ±0.90% ±1.17%
streams/readable-bigunevenread.js n=1000 ** -0.89 % ±0.62% ±0.83% ±1.08%
streams/readable-boundaryread.js type='buffer' n=2000 *** -3.05 % ±0.65% ±0.87% ±1.13%
streams/readable-boundaryread.js type='string' n=2000 0.27 % ±1.33% ±1.77% ±2.30%
streams/readable-from.js type='array' n=10000000 ** -6.09 % ±3.66% ±4.92% ±6.51%
streams/readable-from.js type='async-generator' n=10000000 -0.74 % ±1.44% ±1.93% ±2.53%
streams/readable-from.js type='sync-generator-with-async-values' n=10000000 *** -3.27 % ±1.59% ±2.14% ±2.83%
streams/readable-from.js type='sync-generator-with-sync-values' n=10000000 *** -3.00 % ±0.22% ±0.30% ±0.38%
streams/readable-readall.js n=5000 0.51 % ±1.99% ±2.65% ±3.45%
streams/readable-uint8array.js kind='encoding' n=1000000 * 0.93 % ±0.91% ±1.21% ±1.58%
streams/readable-uint8array.js kind='read' n=1000000 0.54 % ±1.30% ±1.73% ±2.26%
streams/readable-unevenread.js n=1000 -0.16 % ±0.42% ±0.56% ±0.72%
streams/writable-manywrites.js len=1024 callback='no' writev='no' sync='no' n=100000 * -1.90 % ±1.90% ±2.52% ±3.28%
streams/writable-manywrites.js len=1024 callback='no' writev='no' sync='yes' n=100000 *** -1.36 % ±0.59% ±0.78% ±1.02%
streams/writable-manywrites.js len=1024 callback='no' writev='yes' sync='no' n=100000 *** -2.15 % ±1.13% ±1.51% ±1.97%
streams/writable-manywrites.js len=1024 callback='no' writev='yes' sync='yes' n=100000 ** -0.97 % ±0.63% ±0.84% ±1.10%
streams/writable-manywrites.js len=1024 callback='yes' writev='no' sync='no' n=100000 -1.14 % ±2.40% ±3.20% ±4.17%
streams/writable-manywrites.js len=1024 callback='yes' writev='no' sync='yes' n=100000 -0.19 % ±1.46% ±1.94% ±2.53%
streams/writable-manywrites.js len=1024 callback='yes' writev='yes' sync='no' n=100000 *** -3.61 % ±1.27% ±1.70% ±2.23%
streams/writable-manywrites.js len=1024 callback='yes' writev='yes' sync='yes' n=100000 0.18 % ±1.76% ±2.35% ±3.08%
streams/writable-manywrites.js len=32768 callback='no' writev='no' sync='no' n=100000 1.39 % ±2.35% ±3.13% ±4.09%
streams/writable-manywrites.js len=32768 callback='no' writev='no' sync='yes' n=100000 -0.08 % ±1.99% ±2.67% ±3.52%
streams/writable-manywrites.js len=32768 callback='no' writev='yes' sync='no' n=100000 * -3.00 % ±2.33% ±3.10% ±4.03%
streams/writable-manywrites.js len=32768 callback='no' writev='yes' sync='yes' n=100000 0.25 % ±1.96% ±2.63% ±3.47%
streams/writable-manywrites.js len=32768 callback='yes' writev='no' sync='no' n=100000 * -3.12 % ±2.43% ±3.24% ±4.23%
streams/writable-manywrites.js len=32768 callback='yes' writev='no' sync='yes' n=100000 *** -0.87 % ±0.42% ±0.56% ±0.73%
streams/writable-manywrites.js len=32768 callback='yes' writev='yes' sync='no' n=100000 *** -3.44 % ±1.65% ±2.20% ±2.87%
streams/writable-manywrites.js len=32768 callback='yes' writev='yes' sync='yes' n=100000 *** -1.91 % ±1.01% ±1.34% ±1.75%
streams/writable-uint8array.js kind='object-mode' n=50000000 ** 1.12 % ±0.83% ±1.11% ±1.48%
streams/writable-uint8array.js kind='write' n=50000000 ** -0.73 % ±0.53% ±0.71% ±0.94%
streams/writable-uint8array.js kind='writev' n=50000000 -0.26 % ±0.29% ±0.38% ±0.50%
Be aware that when doing many comparisons the risk of a false-positive
result increases. In this case, there are 43 comparisons, you can thus
expect the following amount of false-positive results:
2.15 false positives, when considering a 5% risk acceptance (*, **, ***),
0.43 false positives, when considering a 1% risk acceptance (**, ***),
0.04 false positives, when considering a 0.1% risk acceptance (***)
outdated benchmark result
confidence improvement accuracy (*) (**) (***)
streams/creation.js kind='duplex' n=50000000 *** -10.67 % ±0.75% ±1.01% ±1.31%
streams/creation.js kind='readable' n=50000000 *** -33.14 % ±0.53% ±0.70% ±0.91%
streams/creation.js kind='transform' n=50000000 *** -13.41 % ±2.20% ±2.93% ±3.83%
streams/creation.js kind='writable' n=50000000 *** -17.71 % ±0.64% ±0.85% ±1.10%
streams/destroy.js kind='duplex' n=1000000 *** -13.21 % ±0.33% ±0.44% ±0.58%
streams/destroy.js kind='readable' n=1000000 *** -17.11 % ±1.39% ±1.85% ±2.43%
streams/destroy.js kind='transform' n=1000000 *** -16.09 % ±0.39% ±0.52% ±0.67%
streams/destroy.js kind='writable' n=1000000 *** -18.63 % ±0.87% ±1.17% ±1.53%
streams/pipe-object-mode.js n=5000000 *** 5.21 % ±0.32% ±0.42% ±0.55%
streams/pipe.js n=5000000 *** 2.01 % ±0.53% ±0.71% ±0.93%
streams/readable-async-iterator.js sync='no' n=100000 -0.56 % ±0.91% ±1.21% ±1.58%
streams/readable-async-iterator.js sync='yes' n=100000 *** -3.87 % ±1.89% ±2.52% ±3.28%
streams/readable-bigread.js n=1000 -0.41 % ±0.77% ±1.02% ±1.34%
streams/readable-bigunevenread.js n=1000 -0.30 % ±0.55% ±0.73% ±0.95%
streams/readable-boundaryread.js type='buffer' n=2000 *** -2.37 % ±0.62% ±0.83% ±1.08%
streams/readable-boundaryread.js type='string' n=2000 *** 1.83 % ±0.78% ±1.05% ±1.37%
streams/readable-from.js type='array' n=10000000 *** -4.81 % ±1.35% ±1.79% ±2.34%
streams/readable-from.js type='async-generator' n=10000000 0.16 % ±0.88% ±1.17% ±1.53%
streams/readable-from.js type='sync-generator-with-async-values' n=10000000 -0.22 % ±0.26% ±0.35% ±0.45%
streams/readable-from.js type='sync-generator-with-sync-values' n=10000000 *** -2.73 % ±0.14% ±0.19% ±0.24%
streams/readable-readall.js n=5000 0.42 % ±2.08% ±2.77% ±3.60%
streams/readable-uint8array.js kind='encoding' n=1000000 ** 1.26 % ±0.87% ±1.17% ±1.54%
streams/readable-uint8array.js kind='read' n=1000000 ** -2.36 % ±1.67% ±2.23% ±2.92%
streams/readable-unevenread.js n=1000 0.17 % ±0.78% ±1.03% ±1.34%
streams/writable-manywrites.js len=1024 callback='no' writev='no' sync='no' n=100000 -2.04 % ±2.51% ±3.35% ±4.38%
streams/writable-manywrites.js len=1024 callback='no' writev='no' sync='yes' n=100000 -0.53 % ±0.67% ±0.89% ±1.15%
streams/writable-manywrites.js len=1024 callback='no' writev='yes' sync='no' n=100000 *** -2.09 % ±1.11% ±1.48% ±1.93%
streams/writable-manywrites.js len=1024 callback='no' writev='yes' sync='yes' n=100000 *** -1.40 % ±0.78% ±1.04% ±1.35%
streams/writable-manywrites.js len=1024 callback='yes' writev='no' sync='no' n=100000 -1.29 % ±1.58% ±2.11% ±2.76%
streams/writable-manywrites.js len=1024 callback='yes' writev='no' sync='yes' n=100000 -0.11 % ±0.65% ±0.86% ±1.12%
streams/writable-manywrites.js len=1024 callback='yes' writev='yes' sync='no' n=100000 ** -3.32 % ±2.06% ±2.75% ±3.58%
streams/writable-manywrites.js len=1024 callback='yes' writev='yes' sync='yes' n=100000 *** -2.18 % ±1.01% ±1.35% ±1.76%
streams/writable-manywrites.js len=32768 callback='no' writev='no' sync='no' n=100000 -1.33 % ±1.80% ±2.40% ±3.15%
streams/writable-manywrites.js len=32768 callback='no' writev='no' sync='yes' n=100000 -0.58 % ±1.21% ±1.62% ±2.11%
streams/writable-manywrites.js len=32768 callback='no' writev='yes' sync='no' n=100000 * -2.00 % ±1.92% ±2.55% ±3.32%
streams/writable-manywrites.js len=32768 callback='no' writev='yes' sync='yes' n=100000 * -1.33 % ±1.30% ±1.74% ±2.27%
streams/writable-manywrites.js len=32768 callback='yes' writev='no' sync='no' n=100000 *** -3.34 % ±1.38% ±1.85% ±2.42%
streams/writable-manywrites.js len=32768 callback='yes' writev='no' sync='yes' n=100000 -0.63 % ±0.68% ±0.91% ±1.19%
streams/writable-manywrites.js len=32768 callback='yes' writev='yes' sync='no' n=100000 *** -3.12 % ±1.61% ±2.14% ±2.78%
streams/writable-manywrites.js len=32768 callback='yes' writev='yes' sync='yes' n=100000 -1.07 % ±1.26% ±1.67% ±2.18%
streams/writable-uint8array.js kind='object-mode' n=50000000 -0.03 % ±0.15% ±0.20% ±0.26%
streams/writable-uint8array.js kind='write' n=50000000 -0.04 % ±0.50% ±0.67% ±0.89%
streams/writable-uint8array.js kind='writev' n=50000000 0.09 % ±0.24% ±0.32% ±0.42%
Be aware that when doing many comparisons the risk of a false-positive
result increases. In this case, there are 43 comparisons, you can thus
expect the following amount of false-positive results:
2.15 false positives, when considering a 5% risk acceptance (*, **, ***),
0.43 false positives, when considering a 1% risk acceptance (**, ***),
0.04 false positives, when considering a 0.1% risk acceptance (***)
CI: https://ci.nodejs.org/job/node-test-pull-request/58776/
CI: https://ci.nodejs.org/job/node-test-pull-request/58777/
CI: https://ci.nodejs.org/job/node-test-pull-request/58778/
If I use 1 class I will need to add an if in the hot path (emit)
I need help with reducing the creation time for streams
Cc @nodejs/performance
As a side note, I think we might want to drop captureRejections. It was a nice experiment without major usage.
It's code that sits into a hot path (even if not triggered), so maybe it would help speeding this up a bit.
Would appreciate if someone has an idea to fix the following failure in the tests, the events are shared for some reason
https://github.com/nodejs/node/blob/f6dc68da5ffd5e0caf52d91a8e983fcf91fbb1cd/test/parallel/test-event-emitter-subclass.js#L54-L66
CI: https://ci.nodejs.org/job/node-test-pull-request/58846/
CI: https://ci.nodejs.org/job/node-test-pull-request/58847/
CI: https://ci.nodejs.org/job/node-test-pull-request/58856/
CI: https://ci.nodejs.org/job/node-test-pull-request/58863/
CI: https://ci.nodejs.org/job/node-test-pull-request/58864/
CI: https://ci.nodejs.org/job/node-test-pull-request/58865/
CI: https://ci.nodejs.org/job/node-test-pull-request/58870/