From 64cc066f59f50e29fc3a587a3cfc8b1270eb45cd 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 331006fee03bad..74d1bd44ff0846 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;