Simpleperf is a versatile command-line tool included in the NDK package that lets you perform CPU profiling for Android application processes. This tool can help you to find hot spots (that is, parts of native code that take up the most execution time in your app) for apps written in Java, C/C++, and Kotlin. Events correlated to a hot spot likely point to performance issues, so you should inspect and fix the source of hot spots if you care about your app’s performance.
You can run Simpleperf from any host development platform that the NDK supports. You can get the
Simpleperf tool from NDK r13b and higher (under the
ndk-location/simpleperf/ directory) or as a
prebuilt from AOSP.
To use Simpleperf, you must follow these requirements:
- Use a device running Android 5.0 (API level 21) or higher to profile your app.
- Connect the device to your development machine with a USB debugging connection.
To run the Python scripts for recording and reporting (recommended), install the following on your development machine:
For the latest usage notes, refer to the Simpleperf README.
This section contains basic instructions for profiling an Android app with Simpleperf.
1. Prepare the app for profiling
The app to profile must be debuggable. In the
<application> element of your app manifest, make sure that the android:debuggable attribute
is set to
true. This is already set for you if you are creating a new module in Android Studio.
Depending on whether you are profiling an app with Java or C++ code, you may also need to take these additional steps:
- If you are profiling Java code and are using a device running Android O, you must add the
wrap.shfile to your APK. See the sample Gradle build script for Java code on how to package
wrap.shinto your APK.
- If you are profiling an app that contains C++ code or pre-compiled native libraries:
- Avoid using
-O0optimizations, as this might cause the C++ code to run slow. Instead, use the release build type, as shown in the sample Gradle build script for native code.
- Use native libraries with debug info in the APK wherever possible. See the sample Gradle build script for native code on how to build your APK using unstripped libraries.
- Avoid using
If you want to use Simpleperf to profile an Android app built with Unity, follow these steps to include debuggable symbols.
2. Configure the app profiling session
Simpleperf provides a Python script (
app_profiler.py) to simplify how you run a profiling
session. To configure the behavior of the script, you can modify the properties in the
app_profiler.config file which is located in the
directory on your development machine.
The key properties are listed in the following table.
||Package name of the app to profile.||
||Path of the debuggable APK on your development machine for the app to profile.||
||Path of the Android Studio project on your development machine.||
||Main activity for the app your want to profile.||
||Compiles Dalvik bytecode into native binaries with debug information. If profiling
Java-only code, set to
||Profiling options you want to pass as arguments to the
If you want to record call graph information for the profiling session, see Recording considerations for how to configure your record options.
3. Run the app profiler
To start the profiling session from your development machine, run the
from the command line. You can find the script in the
$ python app_profiler.py
The script performs these actions:
- Pushes a copy of the Simpleperf executable to the Android device, based on the device
architecture (for example, if the target device is based on ARM64, the script copies the
ndk-location/simpleperf/bin/android/arm64/simpleperfexecutable to the device).
- Runs the
simpleperf record' command on the device. If successful, this command generates a
perf.datafile with the collected profile information.
- Sends a copy of the generated
perf.datafile back to the development machine. By default, the file is saved to the
ndk-location/simpleperf/directory. To change the output location, modify the
perf_data_pathproperty in your
4. Generate a profiling report
You can see the profiling report in text mode or in an interactive graphical user interface.
- Text mode: Run the
simpleperf report' command using the Simpleperf executable for your host platform. For example, if your development machine is running Linux, run the report command using
- Graphical mode: Run the
report.pyscript from the command line. The script is located in the
ndk-location/simpleperf/directory. The script also accepts the same arguments as the '
simpleperf report' command.
Simpleperf tips and recipes
If you are just starting out with Simpleperf, here are some commands that you may find particularly useful. For more commands and options, see Simpleperf Command Reference.
Find which shared libraries take the longest to execute
You can run this command to see which
.so files take up the largest percentage of execution
time (based on the number of CPU cycles). This is a good first command to run when starting
your performance analysis session.
$ simpleperf report --sort dso
Find which functions take the longest to execute
Once you have identified which shared library takes most of the execution time, you can run this
command to see the percentage of time spent executing the functions of that
$ simpleperf report --dsos library.so --sort symbol
Find percentage of time spent in threads
Execution time in a
.so file can be split across multiple threads. You can run this command to
see the percentage of time spent in each thread.
$ simpleperf report --sort tid,comm
Find the percentage of time spent in object modules
After finding the threads where most of the execution time is spent, you can use this command to isolate the object modules taking the longest execution time on those threads.
$ simpleperf report --tids threadID --sort dso
See how function calls are related
A call graph provides a visual representation of a stack trace that Simpleperf records during the profiling session. Before you start recording call graph information, see Recording considerations.
You can use the
report -g command to print a call graph to see what
functions are called by other functions. This is useful to determine if a function is slow by
itself, or if it's because one or more of the functions it calls are slow.
$ simpleperf report -g
You can also use the Python script
report.py -g to start an interactive tool that displays
functions. You can click on each function to see how much time is spent in it's children.
Simpleperf supports two primary ways to record the call graph information during a profiling
session, namely DWARF-based (
record --call-graph dwarf or
record -g) and
stack frame pointer-based (
record --call-graph fp).
In general, recording with
--call-graph fp is much faster than with
You should consider using the
--call-graph fp option if you are profiling on devices built on the
AArch-64 architecture (arm64-v8a), but not on devices built on the ARM architecture
(armeabi and armeabi-v7a). This is because devices built on the ARM architecture typically do
not have stack frame registers to support reliable stack unwinding with the
--call-graph fp option.
Instead, if you are profiling on devices built on the ARM architecture, consider using
--call-graph dwarf option. Using the
--call-graph dwarf option enables Simpleperf to
unwind the stack using the
libunwind library. In order to use the
--call-graph dwarf option,
you must provide debug information in your native libraries. For this reason, we recommend that
you build your APK to contain non-stripped native libraries.
Profiling apps built with Unity
If you are profiling an app built with Unity, make sure to build the app to include debuggable symbols by following these steps:
- Open your Android project in the Unity Editor.
- In the Build Settings window for the Android platform, make sure the Development Build option is checked.
- Click on Player Settings and set the Stripping Level property to Disabled.
To report issues or make feature requests, use the
android-ndk/ndk issue tracker on GitHub.