Skip to main content
Version: 0.78

Profiling

Profiling is the process of analyzing an app's performance, resource usage, and behavior to identify potential bottlenecks or inefficiencies. It's worth making use of profiling tools to ensure your app works smoothly across different devices and conditions.

For iOS, Instruments is an invaluable tool, and on Android you should learn to use the Android Studio Profiler.

But first, make sure that Development Mode is OFF! You should see __DEV__ === false, development-level warning are OFF, performance optimizations are ON in your application logs.

Profiling Android UI Performance with System Tracing

Android supports 10k+ different phones and is generalized to support software rendering: the framework architecture and need to generalize across many hardware targets unfortunately means you get less for free relative to iOS. But sometimes, there are things you can improve -- and many times it's not native code's fault at all!

The first step for debugging this jank is to answer the fundamental question of where your time is being spent during each 16ms frame. For that, we'll be using the built-in System Tracing profiler in the Android Studio.

1. Collecting a trace

First, connect a device that exhibits the stuttering you want to investigate to your computer via USB. Open your project's android folder in Android Studio, select your device in the top right pane, and run your project as profileable.

When your app is built as profileable and is running on the device, get your app to the point right before the navigation/animation you want to profile and start the "Capture System Activities" task in the Android Studio Profiler pane.

Once the trace starts collecting, perform the animation or interaction you care about. Then press "Stop recording". You can now inspect the trace directly in the Android Studio. Alternatively, you can select it in the "Past Recordings" pane, press "Export recording", and open it in a tool like Perfetto.

2. Reading the trace

After opening the trace in Android Studio or Perfetto, you should see something like this:

Example

Hint

Use the WASD keys to strafe and zoom.

The exact UI might be different but the instructions below will apply regardless of the tool you're using.

Enable VSync highlighting

Check this checkbox at the top right of the screen to highlight the 16ms frame boundaries:

Enable VSync Highlighting

You should see zebra stripes as in the screenshot above. If you don't, try profiling on a different device: Samsung has been known to have issues displaying vsyncs while the Nexus series is generally pretty reliable.

3. Find your process

Scroll until you see (part of) the name of your package. In this case, I was profiling com.facebook.adsmanager, which shows up as book.adsmanager because of silly thread name limits in the kernel.

On the left side, you'll see a set of threads which correspond to the timeline rows on the right. There are a few threads we care about for our purposes: the UI thread (which has your package name or the name UI Thread), mqt_js, and mqt_native_modules. If you're running on Android 5+, we also care about the Render Thread.

  • UI Thread. This is where standard android measure/layout/draw happens. The thread name on the right will be your package name (in my case book.adsmanager) or UI Thread. The events that you see on this thread should look something like this and have to do with Choreographer, traversals, and DispatchUI:

    UI Thread Example

  • JS Thread. This is where JavaScript is executed. The thread name will be either mqt_js or <...> depending on how cooperative the kernel on your device is being. To identify it if it doesn't have a name, look for things like JSCall, Bridge.executeJSCall, etc:

    JS Thread Example

  • Native Modules Thread. This is where native module calls (e.g. the UIManager) are executed. The thread name will be either mqt_native_modules or <...>. To identify it in the latter case, look for things like NativeCall, callJavaModuleMethod, and onBatchComplete: