From 2e92f6f5d93b5bf098cdc5d8b0dd2ba597457c57 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 a6ef700143ee9f..237a1b96922aef 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;