From 44466063887c464a5fdc2e8b3309f363cc227bc8 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Sat, 18 Dec 2021 17:32:49 +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 --- 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;