Closed undef1ned closed 7 years ago
I can confirm this.. there is a critical performance degradation in 0.27 and 0.28. Reverting to 26.3 fixed it.
In fact TouchableOpacity + Navigation Push while a NativeModule runs in Background results in a 20-60 second lag. 0.26 works like a charm.
I'm experiencing this on iOS as well
👍 ward
@facebook-github-bot label Android
After upgrading to 0.28 I'm experiencing the same problems, so did a roll-back to 0.26.3. However I depend on some features introduced in 0.28
In general, the application runs smooth on LG G4, but on the HTC Desire 500e it's unusable when built with RN 0.28 / 0.27
Thank you for the reporting, it seems a blocking issue to me that will restrain developers to an old version of React Native.
Sorry for the bad label, I wasn't noticed at time that experiencing on iOS too. I'll add some labels and report it in the Core Contributors group.
cc @javache @astreet @lexs
While were reporting, I definitely experienced degradation with 27 (haven't tried 28 yet because of this issue). I'll be rolling back to 26.3 for my next one.
(My app uses both iOS and Android)
I realize this doesn't really help just wanted to point out it's more than 1 person.
We'll need to have a bit more details to investigate this. Why do you think your performance issues are due to native modules? Do you see bigger delays communicating from JS to native or from native to JS?
It would be really helpful if you could take a systrace (https://facebook.github.io/react-native/docs/android-ui-performance.html) of your application while it's behaving badly and share it here.
What @javache said but also, where is the code that is slower running? Is it running inside @ReactMethod
s? A small example would be great, as minimal as you can.
@javache Is there another way to profile Android when systrace is not available (this is the case with many not-rooted phones)
@fab1an experienced the same problem trying to collect the systrace on htc desire...
@lexs @javache I was able to capture the systrace on LG G4 only (4 cpu cores enabled only of 6). On this device it works smooth, so Im not sure this systrace can help to find the problem. RN is 0.28
Captured interaction: navigating to the view with exoPlayer module inside which starts to play the stream
On HTC desire it takes much longer to navigate to the screen, to initialize the native module and finally the video interrupts every 5 seconds or so, like there is not so much cache / memory allocated
@lexs @javache Ok, just systraced the same action with same data on different RN (0.28.0 and 0.26.3) Archive.zip
Even here, on 0.28 there are 3 times more alerts available prior to 0.26.3
unfortunately I still can not systrace on htc desire where the difference is really huge
@undef1ned Yeah, the systraces look very similar. There are more warnings in 0.28 but that might be from flakiness.
I'm still not understanding exactly what is slower. Do you think it's JS being slow or are your native modules slow? Are you feeding the video player from JS? Trying to narrow it down.
@lexs actually I noticed this problem with video player first. It interrupts all the time, even after it was initialised and the stream started to play (I don't do any further communications with the module, it simply streams the video). May-be the app is slower itself as well in other parts which are based on react-native stuff.
I think we need systrace from HTC desire where the difference is really huge
Briefly checked the diff between 0.26 and 0.27 and noticed changes in
https://github.com/facebook/react-native/commit/d4f6f61a96a82a1a35c353b34287d2d819f9478b
It had to add some performance to the old android devices (htc desire is old btw), but actually the performance became slower. May-be this is somehow connected.
ah, the same troubles developers are experiencing on ios devices, so Im not sure :( Currentyl my app is developed for Android, so can't check yet
Is there a way to debug Javascript performance without having systrace available?
I have similar slowness and I have debugged my native modules, they are as fast as they should be. But I have no access to react on the device without systrace.
@fab1an: you shouldn't need a rooted phone to run systrace, and it is our primary way to debug JS and native perf issues. Where are you stuck trying to get a trace?
I'm also not sure what the perf issue actually is and how to repro it. Ideally we'd be able to repro in a sample app or in the open source f8 app so we could do a deep dive in the perf issue that we're seeing.
The issues raised on the thread:
@ndfred:
$ ./systrace.py --time=10 -o /Users/fabian/test.html sched gfx view -a my.package`
ERROR.enabling tracing category "sched"d" is not supported on this device.
No data was captured. Output file was not written.
/* removed 'sched' */
$ ./systrace.py --time=10 -o /Users/fabian/test.html gfx view -a my.package`
ERROR.opening /sys/kernel/debug/tracing/trace_clock: No such file or directory (2)(2)(2)e or directory (2)
No data was captured. Output file was not written.
Looked up /sys/kernel/debug
with adb shell
and it's empty, which means that the kernel of this phone (HUAWEI's Flagship G8) doesn't have tracing enabled.
I run most of my application logic in Kotlin/Java, only the UI in ReactNative, so I would like to profile RN to see which part of my render is slow. (animations are sluggish). I do use react correctly with keys, componentShouldUpdate everywhere and so on.
@ndfred
Well, sample app I've built quickly does not have this lag on both RN versions, so the problem is quite more complex. Hopefully I will manage to make systrace work somehow, but as @fab1an mentioned - it's kernel/device specific :(
I just gave 29 a spin - it works much better then 27 and 28. It's not perfect, but a big plus. Nevertheless i'll also try to compile an example.
// Edit: I was wrong - just had an issue with the new module system. Now everything works and the issue is there again. I'll try to get a systrace
I could dig a bit deeper:
The easiest thing to reproduce it for me is to run the whole thing with debugger enabled. In 26.3 this is working as expected. After upgrading nothing works anymore - it's like stopmotion. Without it's "only" laggy on a galaxy 5.
One Press on a Button -> 30-40 Seconds later some movement gets visible. UI is frozen until then. No Console.log or anything...
This happens for me not always - only if a native module is running in background.
What you're seeing (or not seeing) in this trace is simple navigator.push action after button press. trace.html.zip
@K-Leon: having the debugger enabled means you have a debug bundle and your JS code is running outside of the app which is dramatically different from a production scenario and is not meant to be performant at all. Could you try again with a non-debug bundle and without the debugger attached? If you can get a video capture of the issues that would help too.
Bummer that some phones don't support systrace. The Huawei G8 is a beast though (quad core, 2GB RAM, decent flash) so no reason at all for it to be slow. We got a bunch of second hand Nexus 4 phones from Amazon, they're perfect for debugging performance issues on KitKat and Lollipop and what we consider high-end phones (Galaxy Nexus is what we use for low-end tests).
@ndfred with dev disabled it's fast, but I still would like to profile it to squeeze out milliseconds. It's a very complex business app with dozens of views, partly translucent, partly on top of each other.
I would like to know the performance of details like:
DeviceEventEmitter
or if there is no performance difference between the too.WritableMap
.key
s optimal, how long does layout take to calculateI haven't tried using the Android Studio profiler though, maybe that works.
@ndfred My Point is the degration. I know that Debug Mode is not comparable to Release Build, but If it works in 26.3 and stops working in 27 upwards due to performance issues there happened a really problematic change.
And it's just the here described phenomen in "extreme".
@fab1an: profiling is the way to go, although we've been more successful in finding big chunks of work that we could avoid than micro-optimize calls over the bridge. Glad to hear it is fast with dev disabled, that is our target since that is what is shipping to people.
I wrote about our approach here but happy to give more guidance if needed! BTW the systrace screenshot is the level of detail we are getting, from looking at the traces posted on the thread, they have way less data. Maybe worth adding more systrace categories or maybe we broke some of these is OSS. Happy to help there too if that's the case.
I also checked with @michalgr and indeed if some vendors disable ftrace support in their kernel tracing is impossible (sad trombone). If you can get Nexus devices, they're the best to do perf work.
@K-Leon: I get the productivity issue when things are slow in debug mode, although that would be a very different problem than the app being slow in release (making the remote bridge to Chrome fast vs making the React Native stack fast). Is your app slow in non-dev mode too?
@ndfred: I'm not sure if here's the right place for the question, but I really don't think chats are useful for support and whenever I ask specific questions on SO they won't get answered because most people don't know the internals.
I described my approach already here. I use RN solely for the UI which I update with an immutable state-tree. All the event handling (except animation) is done redux-style in Java (actually Kotlin) because I like the type-safety and for other reasons.
So I have my root-component which listens for setUIState
from the Java side and has an emit
function that calls sends out all events to Native, where I do stuff and call setUIState
again. (I haven't found out how to set props
on the root #8356 so I use setState
which sets props
of the child-tree)
Javascript-side:
emit(eventName, data = {}) {
NativeModules.Controller.uiEvent(eventName, data);
}
componentDidMount() {
this.listener = DeviceEventEmitter.addListener('setUIState', uiState => {
this.setState(uiState);
})
this.emit("init");
}
render() {
return (<MyApp {...this.state}/>)
}
On the native side I have:
@ReactMethod
fun uiEvent(eventName: String, data: ReadableMap) {
/* create an UI state from the event */
val newUIState: WritableMap = ...
/* set the state */
ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
.emit("setUIState", newUIState)
}
I know this is unusual. So everything runs over to the native-side. The state-transition there is assumed to be O(1)
, everything async is taken care of in threads. My performance-related questions are:
uiEvent
with a callback and invoke that callback, or use RCTDeviceEventEmitter
WritableMap
s very expensive? Most events consist only of an eventName, so I could add another emit
function and without the second event-parameter if it's worth it.setState
inside requestAnimationFrame
? props
on the JS-side instead of a root-state
? (#8356)shouldComponentUpdate
).Again sorry for spamming this thread and thanks everyone for their amazing work.
Did anyone try RN 0.29 performance? I found my custom native module quite complex to be upgraded to 0.29 so haven't tested the performance myself yet. May-be someone has some overall experience with 0.29 already...
@K-Leon may-be you've tried released 0.29 version as well?
I did some profiling of 0.29 using AndroidStudio monitor and came up with this: #8670
Just tried react native 0.33 and seems no such issue anymore. Tested on legacy HTC sensation with Android 4.1, video playback does not interrupt
After upgrading to RN 0.27.1 I've noticed huge performance issues with my custom android module. Basically the module represents a video player which streams video over network. The module is based on exoPlayer. I have no any crashes or so, just the video is very laggy and interrupts every time. It's completely unusable. After rolling back to Rn 0.26.3 - everything is fine
Seems custom native modules support was broken