facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
118.37k stars 24.25k forks source link

Native Module performance issues with RN 0.27 (Android) #7995

Closed undef1ned closed 7 years ago

undef1ned commented 8 years ago

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

K-Leon commented 8 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.

oureta commented 8 years ago

I'm experiencing this on iOS as well

lucasfeliciano commented 8 years ago

👍 ward

charpeni commented 8 years ago

@facebook-github-bot label Android

undef1ned commented 8 years ago

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

charpeni commented 8 years ago

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

9mm commented 8 years ago

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.

javache commented 8 years ago

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.

lexs commented 8 years ago

What @javache said but also, where is the code that is slower running? Is it running inside @ReactMethods? A small example would be great, as minimal as you can.

fab1an commented 8 years ago

@javache Is there another way to profile Android when systrace is not available (this is the case with many not-rooted phones)

undef1ned commented 8 years ago

@fab1an experienced the same problem trying to collect the systrace on htc desire...

undef1ned commented 8 years ago

@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

trace.html.zip

undef1ned commented 8 years ago

@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

lexs commented 8 years ago

@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.

undef1ned commented 8 years ago

@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

fab1an commented 8 years ago

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.

ndfred commented 8 years ago

@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:

fab1an commented 8 years ago

@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.

undef1ned commented 8 years ago

@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 :(

K-Leon commented 8 years ago

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

K-Leon commented 8 years ago

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

ndfred commented 8 years ago

@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).

fab1an commented 8 years ago

@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:

I haven't tried using the Android Studio profiler though, maybe that works.

K-Leon commented 8 years ago

@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".

ndfred commented 8 years ago

@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?

fab1an commented 8 years ago

@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:

Again sorry for spamming this thread and thanks everyone for their amazing work.

undef1ned commented 8 years ago

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?

fab1an commented 8 years ago

I did some profiling of 0.29 using AndroidStudio monitor and came up with this: #8670

undef1ned commented 8 years ago

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