Using DDMS to Profile Android Apps

By | July 2, 2010

I like having an idea of how efficient any code I write is, and I like having tools with which to do so. Over the years I’ve accumulated a good gut feeling for what inefficient code looks like. That said, sometimes I have to go spelunking a bit more to find those inefficiencies that aren’t readily apparent and which don’t manifest themselves until it’s too late (read: the app has been deployed to production).

Being new to the Java and Android space, I’ve been flying blind as far as tooling goes for monitoring things like memory usage in the small apps I’ve written. I was pretty happy when I stumbled across the DDMS tool and finally got it to show me just how inefficient one of my prior apps was. This post is a bare bones summary of how I spun up on DDMS and how I used it to help me improve my code.

I’m working in Eclipse on Windows.

DDMS

DDMS stands for “Dalvik Debug Monitor Server” and is a tool that is included in the Android SDK, in the tools/ directory. It can be used to simulate just about anything you’d like on your mobile device, from incoming calls to GPS coordinate reads. A much fuller look at the tool’s capabilities can be found by following the link above. Here we will just review how to use it to profile an application’s memory usage.

An important note here, and one of the primary reasons for all this fun, is that the DDMS tool available in Eclipse can’t profile your application’s memory usage. You have to use the external DDMS tool cited above.

Android Virtual Devices

Android development testing always occurs on what are called Android Virtual Devices – the pretty emulators that spin up whenever you press the run button in Eclipse from an Android application. When working on a Windows XP machine with Eclipse, the files that comprise these virtual devices are found in your C:\Documents and Settings\<user>\.android\avd folder, in subfolders corresponding to the name that you gave your virtual device when you created it in Eclipse. I mention this only because I had forgotten the easy way to determine what test devices you’ve created in Eclipse; namely, clicking on the Window –> Android SDK and AVD Manager menu option.

devices

Once you know the name of the AVD on which you’ve installed the app that you want to profile, you’re ready for the next step.

Starting Your Virtual Device

The DDMS tool can’t attach to your virtual device until you start it. What got me was when I tried to connect to my virtual device after I had started it from Eclipse. The bottom line is that you can only have one primary debugger attached to a virtual device at any time. By starting my device from Eclipse, it’s debugger was attaching first, preventing the external DDMS tool from getting any real data. To avoid this, I started my virtual device from a PowerShell prompt.

manualStart

It’s literally that easy. Give it the usual long time to spin up, and your virtual device will be up and running.

Starting DDMS

To start DDMS, issue the below command.

startDDMS

And then you’ll see something like the below pop up.

ddms

If you don’t see the names of the processes in the emulator node in the upper left side of the window, that probably means you left another debugger attached to the virtual device, which prevented your newly launched instance from getting the information it needs.

Profiling Your App

Now we get to the good stuff. To demonstrate how bad my code is, we’re going to launch the BounceAnimation application that I used to demonstrate some simple animations several posts back. After I launch this app in my virtual device, I can it listed in my list of processes.

newProcess

There are seven tabs on the right hand side of the DDMS tool. Since we are interested in our memory usage, we will only be looking at the Allocation Tracker tab.

allocationTracker

We click the Start Tracking button, wait a bit, and then click the Get Allocations button and we’re off to the races with a slew of information.

initialAllocations

The columns and values are pretty self explanatory – for more information, refer to the Android SDK documentation.

We want to see how the bounce animation application is inefficient. To do this, we have to keep tracking and actually exercise our application. I click on the application five times, running the bounce loop exactly that many times, and then press the Get Allocations button again.

postAllocations

That’s a lot of Paint objects. Looking at the stack trace below that spawned this allocation, we can see that our BounceView.java class is the culprit. Looking at the code, we can see the problem right away.

@Override
protected void onDraw(Canvas canvas) {
    if (_currentX > 0 && _currentY > 0) {
        Paint p = new Paint();
        p.setColor(Color.WHITE);
        p.setTextSize(20);

        canvas.drawText("hey there", _currentX, _currentY, p);
    }
}

In my great wisdom, I’m instantiating a new Paint object every time the onDraw override is being called. Moving this Paint object to the class level instead improves our Paint allocation picture so much so that after restarting my whole debugging stack, kicking off the bounce animation five times and re-querying for allocations, I can’t even find an allocated Paint object.

Hopefully this saves you some time when trying to profile memory allocations in your Android apps!