From d2db72928792b4ce56b4d68d9d029fdb832d48ef Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Sun, 2 Jan 2022 20:58:23 +0530 Subject: [PATCH] timers: use ref counts to count timers 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: https://github.com/nodejs/node/issues/41219 Signed-off-by: Darshan Sen PR-URL: https://github.com/nodejs/node/pull/41231 Reviewed-By: Anatoli Papirovski Reviewed-By: Antoine du Hamel --- lib/internal/bootstrap/node.js | 12 +++++------- lib/internal/timers.js | 21 +++++++++------------ lib/timers.js | 3 --- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index cb11deb69d7ec7..1393cc20f45db6 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -39,9 +39,9 @@ setupPrepareStackTrace(); const { + Array, ArrayPrototypeConcat, - ArrayPrototypeFilter, - ArrayPrototypeMap, + ArrayPrototypeFill, FunctionPrototypeCall, JSONParse, ObjectDefineProperty, @@ -49,7 +49,6 @@ const { ObjectGetPrototypeOf, ObjectPreventExtensions, ObjectSetPrototypeOf, - ObjectValues, ReflectGet, ReflectSet, SymbolToStringTag, @@ -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 diff --git a/lib/internal/timers.js b/lib/internal/timers.js index 8edff995326a01..2441d7b194a72b 100644 --- a/lib/internal/timers.js +++ b/lib/internal/timers.js @@ -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; @@ -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. @@ -478,7 +471,6 @@ function getTimerCallbacks(runNextTicks) { if (destroyHooksExist()) emitDestroy(asyncId); - delete activeTimersMap[asyncId]; outstandingQueue.head = immediate = immediate._idleNext; } @@ -551,7 +543,6 @@ function getTimerCallbacks(runNextTicks) { if (destroyHooksExist()) emitDestroy(asyncId); - delete activeTimersMap[asyncId]; } continue; } @@ -580,7 +571,6 @@ function getTimerCallbacks(runNextTicks) { if (destroyHooksExist()) emitDestroy(asyncId); - delete activeTimersMap[asyncId]; } } @@ -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. @@ -670,9 +667,9 @@ module.exports = { active, unrefActive, insert, - activeTimersMap, timerListMap, timerListQueue, decRefCount, - incRefCount + incRefCount, + getTimerCounts, }; diff --git a/lib/timers.js b/lib/timers.js index 51e8e69d172022..a4543fea1df6bc 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -45,7 +45,6 @@ const { kRefed, kHasPrimitive, getTimerDuration, - activeTimersMap, timerListMap, timerListQueue, immediateQueue, @@ -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); @@ -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;