-
Notifications
You must be signed in to change notification settings - Fork 30k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
timers: Avoid linear scan in _unrefActive.
Before this change, _unrefActive would keep the unrefList sorted when adding a new timer. Because _unrefActive is called extremely frequently, this linear scan (O(n) at worse) would make _unrefActive show high in the list of contributors when profiling CPU usage. This commit changes _unrefActive so that it doesn't try to keep the unrefList sorted. The insertion thus happens in constant time. However, when a timer expires, unrefTimeout has to go through the whole unrefList because it's not ordered anymore. It is usually not large enough to have a significant impact on performance because: - Most of the time, the timers will be removed before unrefTimeout is called because their users (sockets mainly) cancel them when an I/O operation takes place. - If they're not, it means that some I/O took a long time to happen, and the initiator of subsequents I/O operations that would add more timers has to wait for them to complete. With this change, _unrefActive does not show as a significant contributor in CPU profiling reports anymore. Fixes #8160. PR-URL: #8751 Signed-off-by: Timothy J Fontaine <tjfontaine@gmail.com>
- Loading branch information
1 parent
813114d
commit 934bfe2
Showing
2 changed files
with
144 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright Joyent, Inc. and other Node contributors. | ||
// | ||
// Permission is hereby granted, free of charge, to any person obtaining a | ||
// copy of this software and associated documentation files (the | ||
// "Software"), to deal in the Software without restriction, including | ||
// without limitation the rights to use, copy, modify, merge, publish, | ||
// distribute, sublicense, and/or sell copies of the Software, and to permit | ||
// persons to whom the Software is furnished to do so, subject to the | ||
// following conditions: | ||
// | ||
// The above copyright notice and this permission notice shall be included | ||
// in all copies or substantial portions of the Software. | ||
// | ||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN | ||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | ||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
// USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
|
||
/* | ||
* This test is aimed at making sure that unref timers queued with | ||
* timers._unrefActive work correctly. | ||
* | ||
* Basically, it queues one timer in the unref queue, and then queues | ||
* it again each time its timeout callback is fired until the callback | ||
* has been called ten times. | ||
* | ||
* At that point, it unenrolls the unref timer so that its timeout callback | ||
* is not fired ever again. | ||
* | ||
* Finally, a ref timeout is used with a delay large enough to make sure that | ||
* all 10 timeouts had the time to expire. | ||
*/ | ||
|
||
var timers = require('timers'); | ||
var assert = require('assert'); | ||
|
||
var someObject = {}; | ||
var nbTimeouts = 0; | ||
|
||
/* | ||
* libuv 0.10.x uses GetTickCount on Windows to implement timers, which uses | ||
* system's timers whose resolution is between 10 and 16ms. See | ||
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms724408.aspx | ||
* for more information. That's the lowest resolution for timers across all | ||
* supported platforms. We're using it as the lowest common denominator, | ||
* and thus expect 5 timers to be able to fire in under 100 ms. | ||
*/ | ||
var N = 5; | ||
var TEST_DURATION = 100; | ||
|
||
timers.unenroll(someObject); | ||
timers.enroll(someObject, 1); | ||
|
||
someObject._onTimeout = function _onTimeout() { | ||
++nbTimeouts; | ||
|
||
if (nbTimeouts === N) timers.unenroll(someObject); | ||
|
||
timers._unrefActive(someObject); | ||
} | ||
|
||
function startTimer() { timers._unrefActive(someObject); } | ||
|
||
startTimer(); | ||
|
||
setTimeout(function() { | ||
assert.equal(nbTimeouts, N); | ||
}, TEST_DURATION); |