Skip to content

Commit

Permalink
timers: use only a single TimerWrap instance
Browse files Browse the repository at this point in the history
Hang all timer lists off a single TimerWrap and use the PriorityQueue
to manage expiration priorities. This makes the Timers code clearer,
consumes significantly less resources and improves performance.

PR-URL: nodejs#20555
Fixes: nodejs#16105
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
  • Loading branch information
apapirovski committed May 22, 2018
1 parent 6f6f7f7 commit 23a56e0
Show file tree
Hide file tree
Showing 13 changed files with 242 additions and 329 deletions.
14 changes: 11 additions & 3 deletions benchmark/timers/timers-cancel-unpooled.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,26 @@ const assert = require('assert');

const bench = common.createBenchmark(main, {
n: [1e6],
direction: ['start', 'end']
});

function main({ n }) {
function main({ n, direction }) {

const timersList = [];
for (var i = 0; i < n; i++) {
timersList.push(setTimeout(cb, i + 1));
}

var j;
bench.start();
for (var j = 0; j < n + 1; j++) {
clearTimeout(timersList[j]);
if (direction === 'start') {
for (j = 0; j < n; j++) {
clearTimeout(timersList[j]);
}
} else {
for (j = n - 1; j >= 0; j--) {
clearTimeout(timersList[j]);
}
}
bench.end(n);
}
Expand Down
16 changes: 12 additions & 4 deletions benchmark/timers/timers-insert-unpooled.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,26 @@ const assert = require('assert');

const bench = common.createBenchmark(main, {
n: [1e6],
direction: ['start', 'end']
});

function main({ n }) {
function main({ direction, n }) {
const timersList = [];

var i;
bench.start();
for (var i = 0; i < n; i++) {
timersList.push(setTimeout(cb, i + 1));
if (direction === 'start') {
for (i = 1; i <= n; i++) {
timersList.push(setTimeout(cb, i));
}
} else {
for (i = n; i > 0; i--) {
timersList.push(setTimeout(cb, i));
}
}
bench.end(n);

for (var j = 0; j < n + 1; j++) {
for (var j = 0; j < n; j++) {
clearTimeout(timersList[j]);
}
}
Expand Down
22 changes: 8 additions & 14 deletions lib/internal/timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ const {
// Timeout values > TIMEOUT_MAX are set to 1.
const TIMEOUT_MAX = 2 ** 31 - 1;

const unrefedSymbol = Symbol('unrefed');
const kRefed = Symbol('refed');

module.exports = {
TIMEOUT_MAX,
kTimeout: Symbol('timeout'), // For hiding Timeouts on other internals.
async_id_symbol,
trigger_async_id_symbol,
Timeout,
kRefed,
initAsyncResource,
setUnrefTimeout,
validateTimerDuration
Expand All @@ -50,7 +51,7 @@ function initAsyncResource(resource, type) {

// Timer constructor function.
// The entire prototype is defined in lib/timers.js
function Timeout(callback, after, args, isRepeat, isUnrefed) {
function Timeout(callback, after, args, isRepeat) {
after *= 1; // coalesce to number or NaN
if (!(after >= 1 && after <= TIMEOUT_MAX)) {
if (after > TIMEOUT_MAX) {
Expand All @@ -62,7 +63,6 @@ function Timeout(callback, after, args, isRepeat, isUnrefed) {
after = 1; // schedule on next tick, follows browser behavior
}

this._called = false;
this._idleTimeout = after;
this._idlePrev = this;
this._idleNext = this;
Expand All @@ -75,22 +75,16 @@ function Timeout(callback, after, args, isRepeat, isUnrefed) {
this._repeat = isRepeat ? after : null;
this._destroyed = false;

this[unrefedSymbol] = isUnrefed;
this[kRefed] = null;

initAsyncResource(this, 'Timeout');
}

Timeout.prototype.refresh = function() {
if (this._handle) {
// Would be more ideal with uv_timer_again(), however that API does not
// cause libuv's sorted timers data structure (a binary heap at the time
// of writing) to re-sort itself. This causes ordering inconsistencies.
this._handle.start(this._idleTimeout);
} else if (this[unrefedSymbol]) {
getTimers()._unrefActive(this);
} else {
if (this[kRefed])
getTimers().active(this);
}
else
getTimers()._unrefActive(this);

return this;
};
Expand Down Expand Up @@ -122,7 +116,7 @@ function setUnrefTimeout(callback, after, arg1, arg2, arg3) {
break;
}

const timer = new Timeout(callback, after, args, false, true);
const timer = new Timeout(callback, after, args, false);
getTimers()._unrefActive(timer);

return timer;
Expand Down
Loading

0 comments on commit 23a56e0

Please sign in to comment.