-
Notifications
You must be signed in to change notification settings - Fork 24.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
improve interpolation performance with big input range #33598
improve interpolation performance with big input range #33598
Conversation
Thanks for spotting this! I think all of the sanity checks in this file should probably be disabled in release builds. That will also enable dead code stripping to remove these checks. Can you add an |
Base commit: bfc3935 |
Hi @javache, thanks! It feels to me like this could warrant a bigger discussion on
|
Base commit: bfc3935 |
Some invariants are important to keep around in production, because there may be states we really don't want the application to get into and do want to see escalated to crash reporting. Other invariants, like these ones, in my opinion, are more about catching developer errors, and can be skipped in release. The trade-off here is that we may miss some errors if the inputs to the interpolate call are not static, but I think that's reasonable here. |
Cool, thanks for the explanation! 🙏 |
* doesn't cleanly convert to a string, like undefined, null, and object, | ||
* etc. If you really mean this implicit string conversion, you can do | ||
* something like String(myThing) */ | ||
const message = 'inputRange must be monotonically non-decreasing ' + arr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you make this + String(arr)
and remove the FlowFixMe statement?
@javache has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
This pull request was successfully merged by @Almouro in f503b21. When will my fix make it into a release? | Upcoming Releases |
Summary: This drastically improves `Animated.interpolate` performance when `inputRange` has a considerable amount of elements (~100 in my tests). For instance in `ActivityIndicator` inside `react-native-paper`, the input has 144 elements https://github.com/callstack/react-native-paper/blob/main/src/components/ActivityIndicator.tsx#L170. `react-native-elements` has 9k stars, so I'm assuming this is widely used. ### Cause The reason for the performance drop is that if we assume `n` to be the size of the range, calculating `'inputRange must be monotonically non-decreasing ' + arr` essentially calculates `arr.toString()` which has O(n) complexity. Since it is recalculated in a for loop, we end up with `checkValidInputRange` having a O(n²) complexity. Which means ~10k operations if the array has a size close to 100. ## Changelog [General] [Fixed] - Fix performance issue on Animated.interpolate with big input range Pull Request resolved: facebook#33598 Test Plan: [Here's a repo](https://github.com/Almouro/AnimatedInterpolationRepro) reproducing the issue. The branch `fix` includes the fix. Clicking `Interpolate` runs: ```js new Animated.Value(0).interpolate({ inputRange: Array(144) .fill() .map((_, i) => 1 / (i + 1)) .reverse(), outputRange: Array(144) .fill() .map((_, i) => 1 / (i + 1)) ``` Here's a comparison of JS thread perf before the fix and after the fix: - on a Samsung J3 2017 (lower end) - using Flipper and https://github.com/bamlab/react-native-performance) - ` __DEV__` mode deactivated - clicking the button and waiting 15s | Before | After | |----------|:-------------:| | ![image](https://user-images.githubusercontent.com/4534323/162413692-307c2be1-5c7f-4e7f-ba69-8ba8d7c52bda.png) | ![image](https://user-images.githubusercontent.com/4534323/162413842-780f12d2-ce8b-457c-b66c-c6d86f14ed28.png)| The error still throws if `inputRange` is incorrect: <img width="517" alt="image" src="https://user-images.githubusercontent.com/4534323/162439219-6ce120ae-98e5-496b-899a-492978689d6d.png"> However if `__DEV__` mode is deactivated, no error is thrown Reviewed By: yungsters Differential Revision: D35507441 Pulled By: javache fbshipit-source-id: 36ac49422f7a42d247130c42d12248b2be1232c6
Summary
This drastically improves
Animated.interpolate
performance wheninputRange
has a considerable amount of elements (~100 in my tests).For instance in
ActivityIndicator
insidereact-native-paper
, the input has 144 elements https://github.com/callstack/react-native-paper/blob/main/src/components/ActivityIndicator.tsx#L170.react-native-elements
has 9k stars, so I'm assuming this is widely used.Cause
The reason for the performance drop is that if we assume
n
to be the size of the range, calculating'inputRange must be monotonically non-decreasing ' + arr
essentially calculatesarr.toString()
which has O(n) complexity.Since it is recalculated in a for loop, we end up with
checkValidInputRange
having a O(n²) complexity. Which means ~10k operations if the array has a size close to 100.Changelog
[General] [Fixed] - Fix performance issue on Animated.interpolate with big input range
Test Plan
Here's a repo reproducing the issue.
The branch
fix
includes the fix.Clicking
Interpolate
runs:Here's a comparison of JS thread perf before the fix and after the fix:
__DEV__
mode deactivatedThe error still throws if
inputRange
is incorrect:However if
__DEV__
mode is deactivated, no error is thrown