From 385dd59c0abf625fcd9dae9c7e97a601ed995bf7 Mon Sep 17 00:00:00 2001 From: kewde Date: Mon, 10 Feb 2025 03:43:58 -0800 Subject: [PATCH] perf: fast _getFreeIndex (#48925) Summary: The performance of `_getFreeIndex` is quite terrible since the `timersID` array can get quite large when you spawn a lot of promises or timers. We profiled our application for 28 seconds on RN 0.71.11 and noticed that the `indexOf` into this array was consuming almost a second. The hermes version that we are using has a pretty slow `indexOf` compared to other engines, and the static hermes will improve it by 12x but for the time being, this is a perf issue. https://github.com/facebook/hermes/pull/1447 We avoid having to use `indexOf` by maintaining a list of the free ids. **Before - Samsung Galaxy A52 for 28 seconds of profiling** ![image](https://github.com/user-attachments/assets/e669ed62-58d8-4d11-8a85-a82816b3792d) **After - Samsung Galaxy A52 for 28 seconds of profiling** ![image](https://github.com/user-attachments/assets/48cd369f-0887-4683-920c-43068d0228b0) ## Changelog: [INTERNAL] [FIXED] - Improve performance of _getFreeIndex Pull Request resolved: https://github.com/facebook/react-native/pull/48925 Test Plan: - Tests pass, promises resolve and reject correctly, setTimeout works as expected Reviewed By: javache Differential Revision: D69059102 Pulled By: cipolleschi fbshipit-source-id: d7de2c4adcf4dfc1d15e597e2a801e23c8d652aa --- .../react-native/Libraries/Core/Timers/JSTimers.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/react-native/Libraries/Core/Timers/JSTimers.js b/packages/react-native/Libraries/Core/Timers/JSTimers.js index 546fce413aa..7987104f86c 100644 --- a/packages/react-native/Libraries/Core/Timers/JSTimers.js +++ b/packages/react-native/Libraries/Core/Timers/JSTimers.js @@ -36,6 +36,7 @@ const IDLE_CALLBACK_FRAME_DEADLINE = 1; const callbacks: Array = []; const types: Array = []; const timerIDs: Array = []; +const freeIdxs: Array = []; let reactNativeMicrotasks: Array = []; let requestIdleCallbacks: Array = []; const requestIdleCallbackTimeouts: {[number]: number, ...} = {}; @@ -47,11 +48,11 @@ let hasEmittedTimeDriftWarning = false; // Returns a free index if one is available, and the next consecutive index otherwise. function _getFreeIndex(): number { - let freeIndex = timerIDs.indexOf(null); - if (freeIndex === -1) { - freeIndex = timerIDs.length; + const freeIdx = freeIdxs.pop(); + if (freeIdx === undefined) { + return timerIDs.length; } - return freeIndex; + return freeIdx; } function _allocateCallback(func: Function, type: JSTimerType): number { @@ -171,6 +172,7 @@ function _clearIndex(i: number) { timerIDs[i] = null; callbacks[i] = null; types[i] = null; + freeIdxs.push(i); } function _freeCallback(timerID: number) {