Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
nodeLinker: node-modules
enableImmutableInstalls: false
122 changes: 113 additions & 9 deletions docs/profiling.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ title: 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](profiling.md#profiling-android-ui-performance-with-system-tracing).
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!**](performance.md#running-in-development-mode-devtrue).

## Profiling Android UI Performance with System Tracing

:::caution Systrace Deprecation Notice
Systrace is deprecated as of React Native 0.82. For modern Android profiling, use [Android Studio Profiler](#profiling-android-ui-performance-with-system-tracing) instead.
:::

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](https://developer.android.com/studio/profile).
Expand All @@ -25,9 +29,9 @@ Once the trace starts collecting, perform the animation or interaction you care

### 2. Reading the trace

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

![Example](/docs/assets/SystraceExample.png)
![Android Studio Profiler Example](/docs/assets/SystraceExample.png)

:::note Hint
Use the WASD keys to strafe and zoom.
Expand All @@ -36,9 +40,9 @@ 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.

:::info Enable VSync highlighting
Check this checkbox at the top right of the screen to highlight the 16ms frame boundaries:
Check this option in Android Studio Profiler to highlight the 16ms frame boundaries:

![Enable VSync Highlighting](/docs/assets/SystraceHighlightVSync.png)
![Enable Frame Timing](/docs/assets/SystraceHighlightVSync.png)

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.
:::
Expand All @@ -49,19 +53,19 @@ Scroll until you see (part of) the name of your package. In this case, I was pro

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.** This is where standard android measure/layout/draw happens. The thread name on the right will be your package name 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](/docs/assets/SystraceUIThreadExample.png)

- **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.** This is where JavaScript is executed. The thread name will be either `mqt_js` or similar. To identify it, look for JavaScript execution patterns:

![JS Thread Example](/docs/assets/SystraceJSThreadExample.png)

- **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`:
- **Native Modules Thread.** This is where native module calls (e.g. the `UIManager`) are executed. Look for native bridge communication patterns:

![Native Modules Thread Example](/docs/assets/SystraceNativeModulesThreadExample.png)

- **Bonus: Render Thread.** If you're using Android L (5.0) and up, you will also have a render thread in your application. This thread generates the actual OpenGL commands used to draw your UI. The thread name will be either `RenderThread` or `<...>`. To identify it in the latter case, look for things like `DrawFrame` and `queueBuffer`:
- **Bonus: Render Thread.** If you're using Android L (5.0) and up, you will also have a render thread in your application. This thread generates the actual OpenGL commands used to draw your UI. Look for GPU-related activities:

![Render Thread Example](/docs/assets/SystraceRenderThreadExample.png)

Expand Down Expand Up @@ -137,3 +141,103 @@ Make sure you select "Find CPU Hotspots **(Java/Kotlin Recording)**" rather than
Perform the interactions and press "Stop recording". Recording is resource-intensive, so keep the interaction short. You can then either inspect the resulting trace in the Android Studio or export it and open it in an online tool like [Firefox Profiler](https://profiler.firefox.com/).

Unlike System Trace, CPU hotspot profiling is slow so it won't give you accurate measurements. However, it should give you an idea of what native methods are being called, and where the time is being spent proportionally during each frame.

## Chrome DevTools

Chrome DevTools provides powerful profiling capabilities for JavaScript performance analysis in React Native apps.

### Setup

1. Enable Chrome DevTools in your React Native app by shaking the device and selecting "Debug"
2. This opens a Chrome tab with DevTools connected to your app

### Performance Profiling

1. Open the **Performance** tab in DevTools
2. Click the record button and perform the actions you want to profile
3. Stop recording to analyze the performance trace

### Key Features

- **CPU Profiling**: Identify JavaScript functions consuming CPU time
- **Memory Profiling**: Track memory usage and detect leaks
- **Network Monitoring**: Analyze network requests
- **Timeline Analysis**: Visualize main thread activity

## React DevTools

React DevTools is specifically designed for debugging React applications and provides insights into component performance.

### Installation

```bash
npm install -g react-devtools
```

### Usage

1. Start React DevTools:

```bash
react-devtools
```

2. In your React Native app, enable debugging mode
3. React DevTools will automatically connect

### Profiling Features

- **Component Profiler**: Measure render times and identify slow components
- **Flame Graph**: Visualize component render hierarchy
- **Interactions Tracking**: Monitor user interactions and their impact
- **Component Inspection**: Examine component props, state, and hooks

## iOS Instruments

Instruments is Apple's powerful profiling tool for iOS applications, providing deep system-level insights.

### Launching Instruments

1. Open Xcode
2. Go to **Xcode > Open Developer Tool > Instruments**
3. Choose your profiling template

### Key Instruments for React Native

- **Time Profiler**: Identify CPU bottlenecks
- **Allocations**: Track memory usage
- **Core Animation**: Monitor UI performance
- **Network**: Analyze network activity
- **Energy Log**: Monitor battery usage

### Profiling Workflow

1. Select your iOS device and app
2. Choose appropriate instruments
3. Start recording
4. Perform the actions to profile
5. Analyze the collected data

## Migration from Systrace

If you're migrating from Systrace to modern profiling tools:

### For Android:

- **Replace Systrace** with **Android Studio Profiler** for system-level tracing
- **Use Flipper** for comprehensive app debugging and profiling
- **Combine with Chrome DevTools** for JavaScript performance analysis

### For iOS:

- **Continue using Instruments** for system profiling
- **Add Flipper** for enhanced debugging capabilities
- **Use React DevTools** for component-level performance insights

### Best Practices:

1. Use platform-specific tools for native performance issues
2. Combine multiple tools for comprehensive analysis
3. Profile on actual devices rather than simulators
4. Test under realistic conditions and data loads
5. Monitor both development and production builds
4 changes: 4 additions & 0 deletions docs/systrace.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ id: systrace
title: Systrace
---

:::caution Deprecated
Systrace is deprecated as of React Native 0.82. For modern Android profiling, use [Android Studio Profiler](profiling.md#profiling-android-ui-performance-with-system-tracing) instead. Systrace may be removed in future versions.
:::

`Systrace` is a standard Android marker-based profiling tool (and is installed when you install the Android platform-tools package). Profiled code blocks are surrounded by start/end markers which are then visualized in a colorful chart format. Both the Android SDK and React Native framework provide standard markers that you can visualize.

## Example
Expand Down
Loading