Performance Debugging of Android* Applications

Published: 11/03/2011, Last Updated: 11/03/2011


Developing responsive applications is critical in creating an enjoyable user experience. With the components available in the Android* SDK, the task of debugging performance issues is made easier by offering simple to use performance analysis tools. In this article we will look at the different tools available for troubleshooting and debugging performance issues or squeezing out a little more performance from a completed application. We will not go into great depths but take a high level approach at how these tools might be used on your application.

We will be demonstrating the tools from within Eclipse ; you can install the ADT plugin by following the directions in the article ADT Plugin for Eclipse*.


DDMS is a Google*-provided application that works as a standalone tool and also comes integrated into Eclipse* via the ADT Eclipse* plugin. It provides a couple of great features that will quickly give you an idea of where your application is spending its time.

Thread Updates

The thread monitor and profiling view in DDMS is useful for applications that manage a lot of threads. To enable, click the Update Threads icon to get started.

Figure 1

This enables the window shown below to display names and some other details of all the threads for the selected VM process.

Figure 2

utime and stime represent the total time spent in that thread running user code (utime) and system code (stime) in "jiffies". The duration of a jiffy is defined by the system but a value of 10ms is typical. The asterisk indicates a daemon thread; the status native means the thread is executing native code. Looking closer at the sample data above, it is apparent that besides the main thread of the app consuming a significant amount of time an unusual amount of time is spent doing GC. A closer look at how the application is handling object creation might be a good idea for increasing performance.

Heap Tools

Heap View

Click on the Update Heap button to get information about heap allocations in the selected VM.

Figure 3

Figure 4

Click on "Cause GC" to get started. Details of the heap are given along with a graph of allocation sizes for a particular allocation type. If you have an allocation leak, this might be a good place to start looking, watch the overall trend in Heap Size to make sure it does not perpetually keep growing during the application run.

Allocation Tracker

The next level of detail about allocations is shown in the Allocation Tracker view. Click on "Start Tracking", perform an action in the application and then click on "Get Allocations".

Figure 5

The list presented is in allocation order with the most recent allocation displayed first. Highlighting it will give you a stack trace of how that allocation was created.

Looking closer at the allocation details it looks like the following code has room for improvement:

dataStr += String.format(" Std. Dev.: %.3f, %.3f, %.3f\n", devX, devY, devZ);

Refactoring into something like the code below is straightforward and saves on overhead needed to construct a temporary char[].

dataStrBuilder.append(String.format(" Std. Dev.: %.3f, %.3f, %.3f\n", devX, devY, devZ));

Method Profiling

Method Profiling is a tool within DDMS that is useful for getting a quick overview of where time is spent in your application and can also be used for closer inspection of time-critical functions.

Figure 6

With your application running and ideally performing some interesting task that you would like to get more performance data about, Click on "Start Method Profiling". The profiler will only collect a small amount of data (have not seen more that 2 or 3 seconds) so after a few moments click the icon again to stop collection. Activating the method profiler from within DDMS causes the tool to automatically use internal storage to store the profiling results and when the capture is complete, will send them back to host for further analysis.

The IDE will automatically launch the Traceview window and allow you to analyze the results from right within the IDE (Figure 7).

Figure 7

Interpreting the results is the most interesting part. Clicking on method calls in the bottom pane will create a hierarchy, showing you the current method, parent(s) that call this method and then the children methods called from within the selected method.

In this application under test I have selected the onSensorChanged method. This is the method invoked by the SensorManager API when you register to receive notification from a sensor type. The calling method here is handleMessage and comes from the OS, so starting with my implementation method is a great focal point. The children are sorted by percentage time spent "Inclusive" of the method. Inclusive here indicates the time spent within that method and all children calls of that method. So for the onSensorChanged call, over 70% of the time was spent in calcStandardDeviation and averageSamples, I might expect the call to calculate a standard deviation to take a more significant amount of time than just averaging samples so with this new information I could go and look closer at my implementation and identify code optimizations.

For a more detailed explanation of Traceview check out the article Profiling with Traceview and dmtracedump

Profiling API

To capture method profiling details with more accuracy calls can be made within code to start and stop profiling. You will need to have an SD card mounted in the device to use this method. Here is an example of adding the hooks to get a better idea about my sensor handling code:

	private static boolean doOnce = true;
	public void onSensorChanged(SensorEvent event) {
		if ( doOnce ) {
		Code under test…

		if ( doOnce ){
			doOnce = false;

The trace file defaults to /mnt/sdcard/dmtrace.trace and can be pulled off the device with:

adb pull /mnt/sdcard/dmtrace.trace.

Run the standalone Traceview tool "traceview C:\dmtrace.trace" and it will launch a UI similar to the one embedded in Eclipse.

Layout UI Tools


Whenever I am getting close to calling an application finished I like to look for easy performance gains in the UI layout of activities. The tool layoutopt will analyze your layout files and point out potential performance issues. It is talked about in this blog and doc reference let’s take a quick look at how to use the tool. The command line usage looks like this:

layoutopt.bat C:\Projects\workspace\DeviceInformation\res

Note: I placed the Android* SDK tools directory in my path. It also looks like the tool only works when you specify the full path of the directory you wish to analyze.

An example of output:

23:23 This TextView layout or its LinearLayout parent is useless
16:19 This LinearLayout layout or its LinearLayout parent is useless
17:20 This LinearLayout layout or its LinearLayout parent is useless

The X:Y is the starting and ending line of the XML tags corresponding to the issue. The superfluous layouts pointed out above add to the overall load time of the activity and is an easy way to make your activity load a little faster.

Hierarchy Viewer

Another useful tool in debugging performance issues in layouts is the Hierarchy Viewer tool. This application will only connect to a developer version of the Android* OS, so without access to a development device the easiest way to use it is with the emulator. Run the tool by command line:



Hopefully I have given you some new tools and knowledge in your quest for better performing applications. Besides using these tools to see where you might be able to make some gains, many performance improvements can be made at the code level, the article Designing for Performance is a great place to learn more about some of the common performance coding techniques.

Here are some additional articles that include more in depth coverage and other tips and tricks:

Designing for Responsiveness

Windows* Background & UI Speed


Product and Performance Information


Intel's compilers may or may not optimize to the same degree for non-Intel microprocessors for optimizations that are not unique to Intel microprocessors. These optimizations include SSE2, SSE3, and SSSE3 instruction sets and other optimizations. Intel does not guarantee the availability, functionality, or effectiveness of any optimization on microprocessors not manufactured by Intel. Microprocessor-dependent optimizations in this product are intended for use with Intel microprocessors. Certain optimizations not specific to Intel microarchitecture are reserved for Intel microprocessors. Please refer to the applicable product User and Reference Guides for more information regarding the specific instruction sets covered by this notice.

Notice revision #20110804