Skip to content

Commit

Permalink
timers: use ref counts to count timers
Browse files Browse the repository at this point in the history
The additional objects that were getting added and deleted from the
activeTimersMap object were slowing down the rest of the timers code,
so this change falls back to using the ref counts to count the active
timers inside process.getActiveResourcesInfo().

Fixes: nodejs#41219

Signed-off-by: Darshan Sen <[email protected]>

PR-URL: nodejs#41231
Reviewed-By: Anatoli Papirovski <[email protected]>
Reviewed-By: Antoine du Hamel <[email protected]>
  • Loading branch information
RaisinTen authored and Linkgoron committed Jan 31, 2022
1 parent 1572876 commit 5b2bef9
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 22 deletions.
12 changes: 5 additions & 7 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,16 @@
setupPrepareStackTrace();

const {
Array,
ArrayPrototypeConcat,
ArrayPrototypeFilter,
ArrayPrototypeMap,
ArrayPrototypeFill,
FunctionPrototypeCall,
JSONParse,
ObjectDefineProperty,
ObjectDefineProperties,
ObjectGetPrototypeOf,
ObjectPreventExtensions,
ObjectSetPrototypeOf,
ObjectValues,
ReflectGet,
ReflectSet,
SymbolToStringTag,
Expand Down Expand Up @@ -156,13 +155,12 @@ const rawMethods = internalBinding('process_methods');
process._getActiveHandles = rawMethods._getActiveHandles;

process.getActiveResourcesInfo = function() {
const timerCounts = internalTimers.getTimerCounts();
return ArrayPrototypeConcat(
rawMethods._getActiveRequestsInfo(),
rawMethods._getActiveHandlesInfo(),
ArrayPrototypeMap(
ArrayPrototypeFilter(ObjectValues(internalTimers.activeTimersMap),
({ resource }) => resource.hasRef()),
({ type }) => type));
ArrayPrototypeFill(new Array(timerCounts.timeoutCount), 'Timeout'),
ArrayPrototypeFill(new Array(timerCounts.immediateCount), 'Immediate'));
};

// TODO(joyeecheung): remove these
Expand Down
21 changes: 9 additions & 12 deletions lib/internal/timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,6 @@ const kRefed = Symbol('refed');
// Create a single linked list instance only once at startup
const immediateQueue = new ImmediateList();

// Object map containing timers
//
// - key = asyncId
// - value = { type, resource }
const activeTimersMap = ObjectCreate(null);

let nextExpiry = Infinity;
let refCount = 0;

Expand All @@ -166,7 +160,6 @@ function initAsyncResource(resource, type) {
resource[trigger_async_id_symbol] = getDefaultTriggerAsyncId();
if (initHooksExist())
emitInit(asyncId, type, triggerAsyncId, resource);
activeTimersMap[asyncId] = { type, resource };
}

// Timer constructor function.
Expand Down Expand Up @@ -478,7 +471,6 @@ function getTimerCallbacks(runNextTicks) {

if (destroyHooksExist())
emitDestroy(asyncId);
delete activeTimersMap[asyncId];

outstandingQueue.head = immediate = immediate._idleNext;
}
Expand Down Expand Up @@ -551,7 +543,6 @@ function getTimerCallbacks(runNextTicks) {

if (destroyHooksExist())
emitDestroy(asyncId);
delete activeTimersMap[asyncId];
}
continue;
}
Expand Down Expand Up @@ -580,7 +571,6 @@ function getTimerCallbacks(runNextTicks) {

if (destroyHooksExist())
emitDestroy(asyncId);
delete activeTimersMap[asyncId];
}
}

Expand Down Expand Up @@ -648,6 +638,13 @@ class Immediate {
}
}

function getTimerCounts() {
return {
timeoutCount: refCount,
immediateCount: immediateInfo[kRefCount],
};
}

module.exports = {
TIMEOUT_MAX,
kTimeout: Symbol('timeout'), // For hiding Timeouts on other internals.
Expand All @@ -670,9 +667,9 @@ module.exports = {
active,
unrefActive,
insert,
activeTimersMap,
timerListMap,
timerListQueue,
decRefCount,
incRefCount
incRefCount,
getTimerCounts,
};
3 changes: 0 additions & 3 deletions lib/timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ const {
kRefed,
kHasPrimitive,
getTimerDuration,
activeTimersMap,
timerListMap,
timerListQueue,
immediateQueue,
Expand Down Expand Up @@ -88,7 +87,6 @@ function unenroll(item) {
// Fewer checks may be possible, but these cover everything.
if (destroyHooksExist() && item[async_id_symbol] !== undefined)
emitDestroy(item[async_id_symbol]);
delete activeTimersMap[item[async_id_symbol]];

L.remove(item);

Expand Down Expand Up @@ -331,7 +329,6 @@ function clearImmediate(immediate) {
if (destroyHooksExist() && immediate[async_id_symbol] !== undefined) {
emitDestroy(immediate[async_id_symbol]);
}
delete activeTimersMap[immediate[async_id_symbol]];

immediate._onImmediate = null;

Expand Down

0 comments on commit 5b2bef9

Please sign in to comment.