status-im / status-mobile

a free (libre) open source, mobile OS for Ethereum
https://status.app
Mozilla Public License 2.0
3.88k stars 983 forks source link

[Perf] Test hypothesis 1: RN Bridge render bottleneck #2963

Closed oskarth closed 6 years ago

oskarth commented 6 years ago

Identified Behavior

Toggling between chat list and chat tabs is noticeably laggy on many devices. Compare with Telegram e.g. Additionally, this might also impact other common transitions.

Hypothesis

Bad performance for toggling between tabs is due to RN Bridge roundtrips being a bottleneck for rendering.

(This is a common performance bottleneck for React Native programs.)

Assumptions

1) Assuming this is still a critical problem for end user 2) Assuming it is reasonably easy to fixable

Experiment

Use Spy or rn-snoopy to verify RN bridge roundtrips is the bottleneck.

Additionally, consider making use of re-frisk or manual timers to supplement above.

Acceptance critiera

Notes

See

oskarth commented 6 years ago

@rasom Do you want to own this issue? Do you agree with it?

@annadanchenko Concurrently with testing of this hypothesis, can you please confirm this is still a problem for end users on our supported devices?

rasom commented 6 years ago

@oskarth yes and yes

oskarth commented 6 years ago

Use Spy or rn-snoopy to verify RN bridge roundtrips is the bottleneck.

One problem with this experiment setup is that a lot of calls, as @rasom pointed out, aren't bidirectional, e.g. some are async/unidirectional. This means it isn't always straightforward to see what the cost of each "bridge crossing".

@rasom You've posted a bunch of observations from this in Slack, would you mind posting a summary of things you found in this issue so we don't lose it?

rasom commented 6 years ago

To sum up communication through RN bridge, we have the next types of messages:

  1. status-module The main concern was related to the way how we use web3, but it seems that regardless of number of incoming messages we don’t have more than 6-8 in/out RN bridge messages related to this module.

  2. Timing/JSTimers This module is used by animation (not native), when we call setTimeout/setInterval explicitly and under the hood by core.async. Right now we have 20-24 messages per second related to this module. So we can define a threshold about 50 mps which means that if we have more than 50 mps for this module something suspicious is happening, and this will trigger some notification in app (in dev mode).

  3. websocket Is used only in develop mode for dev tools and probably figwheel/re-frisk

  4. ui-manager Most of calls related to this module happen on navigation. As far as I can say we have something similar to direct dependency between the number of these calls and duration of navigation between screens. We also can define a threshold for this type of messages, I suppose that it should be about 40 for Android and ~100 on iOS. That’s the numbers when delay before rendering a new screen starts being noticeable (anyway exact numbers TBD)

___ ____develop___ experiment/nav-groups
chats -> console chat updateView 7 createView   205 setChildren  159 Total: 373 updateView 12 Create view 80  setChildren 58  Total: 150
chats -> profile updateView 10 createView 89 setChildren 62 Total: 161 updateView 12 createView 9 setChildren 5 Total: 26
profile -> chats updateView 10 Createview 58 setChildren. 41 Total: 109 updateView 12 createView 10 setChildren 6 Total: 28
  1. touches These messages happen when we touch screen, so if we touch it a lot there can be a lot of them but I doubt that they have serious impact on perf.

  2. native-animation Messages related to animation with setNativeDriver=true.

  3. keyboard-observer We explicitly call this module once in root element, then it also is called by FlatList. Nothing important, but it looked for suspicious at first glance because I was under impression the we call it for no reason. But we don’t.

  4. There are also different messages similar to RCTEventEmitter.receiveEvent([23,”topLayout" Many of them happens when animation with setNativeDriver=false is used, so in most cases we can notice same stuff by watching Timing/JSTimers