-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
http/net: _unrefActive() is extremely expensive #8160
Description
This probably affects master as well but I'm reporting this for v0.10. With any HTTP-heavy benchmark, exports._unrefActive()
from lib/timers.js shows up high on the list of cost centers. Case in point:
1496 10.4% LazyCompile: *exports._unrefActive timers.js:431
607 40.6% LazyCompile: *onread net.js:496
579 38.7% LazyCompile: *Socket._write net.js:619
554 95.7% LazyCompile: *Writable.write _stream_writable.js:163
554 100.0% LazyCompile: *Socket.write net.js:612
NB: That's from an application that puts together a multi-kilobyte SOAP response. That's an expensive operation but _unrefActive() still manages to dominate the list of most expensive functions.
There are two issues here, I think:
- The efficiency of _unrefActive()'s implementation leaves much to be desired.
- lib/net.js frequently calls _unrefActive() an ungodly number of times (for just about every I/O operation, something that really hurts with busy connections.)
I'd like to start a discussion on how to best fix that.
For 1, stripping _unrefActive() from unnecessary cruft seems like a first good step, maybe followed by switching to a timer wheel.
For 2, I'm less sure; the easiest solution I can think of (that is still provably correct and performs well) is to replace the timers._unrefActive(this)
calls with something like this.nevents += 1
. Then, when the timer expires:
- Check if
this.nevents > 0
. - If true, restart the timer.
- If false, emit the timeout event.
That should greatly reduce the frequency of the (linear) scan over the timer list.
Thoughts, @indutny and @tjfontaine and anyone else who wants to chime in?