Skip to content

Bridge is 7x slower to send an array x versus JSON.stringify(x) to an Android native component #31771

@arvoelke

Description

@arvoelke

Description

Sending an array x to an Android native component is incredibly slow. The overhead is roughly 25-26 ms just to send a single array of 16,384 integers.

However, if I send JSON.stringify(x) instead of x then it takes only 3-4 ms, even when including the JSON serialization in the timing! That is roughly 7x faster.

This does not make much sense as the serialization should be slowing things down, and the volume of data being transmitted across the bridge should also be significantly larger due to it being encoded as an ASCII string.

Even if there is a good reason for this performance penalty, ideally the framework should be doing whatever serialization and deserialization across the bridge is most efficient. That is, if it is more efficient to transmit strings from JS to Java under the hood, then the react-native bridge should take care of that for the user, rather than requiring the user to discover this and perform this counterintuitive optimization themselves. Perhaps the user could hint to the framework what kind of protocol to use under the hood depending on the type of array. Alternatively, this might point to some performance regression in how arrays are currently being handled by the bridge and some aspect of the current implementation that could be improved.

Note I am using Xiaomi 8 running Android 10, with JS dev mode disabled and no debugging nor console logging.

React Native version:

System:
    OS: Linux 5.4 Ubuntu 18.04.3 LTS (Bionic Beaver)
    CPU: (24) x64 AMD Ryzen 9 3900X 12-Core Processor
    Memory: 47.00 GB / 62.82 GB
    Shell: 4.4.20 - /bin/bash
  Binaries:
    Node: 14.17.1 - /usr/bin/node
    Yarn: 1.22.10 - /usr/bin/yarn
    npm: 7.17.0 - /usr/bin/npm
    Watchman: Not Found
  SDKs:
    Android SDK: Not Found
  IDEs:
    Android Studio: Not Found
  Languages:
    Java: 1.8.0_292 - /usr/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 17.0.1 => 17.0.1 
    react-native: 0.64.2 => 0.64.2 
  npmGlobalPackages:
    *react-native*: Not Found

Steps To Reproduce

Provide a detailed list of steps that reproduce the issue.

  1. Make a hello world App.js containing the code:
...
  componentDidMount() {
      this.profileNative();
  }

  makeRandomSignal() {
    var sample = [];
    for (var i = 0; i < 16384; i++) {
      sample[i] = 127;
    }
    return sample;
  }

  profileNative() {
    const x = this.makeRandomSignal();
    var tBegin = global.performance.now();
    MyNativeComponent.go(x, r => {
      var output = global.performance.now() - tBegin;
      // Display output value in app (e.g., with this.setState)
      this.profileNative();
    });
  }
...
  1. Make an Android native component (MyNativeComponent) containing the go implementation:
...
    @ReactMethod
    public void go(ReadableArray x, Callback callback) {
        callback.invoke("");
    }
...

Running this on my phone reports roughly 25-26 ms in overhead.

  1. Now simply change go(x, ...) to go(JSON.stringify(x), ...) in App.js and change public void go(ReadableArray x, ...) to public void go(String x, ...). As in:
...
    MyNativeComponent.go(JSON.stringify(x), r => {
...
...
    @ReactMethod
    public void go(String x, Callback callback) {
        callback.invoke("");
    }
...

And the reported timing drops to roughly 3-4 ms.

Expected Results

I expected the additional volume of data and JSON serialization to result in more overhead -- not 7x less. There should be a way to send this array in 3 ms without jumping through hoops to serialize it as a string.

Snack, code example, screenshot, or link to a repository:

See above.

I believe this issue is closely related to #10504. That issue was closed without any resolution or improvement.

I could provide a stand-alone regression test if I had some starting point to work off, but I believe the above is enough to show that there is a serious problem that should not be expected, and the steps that can be taken to reproduce this problem.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions