Depuração de Desempenho de Aplicativos Android*

Visão geral

O desenvolvimento de aplicativos responsivos é fundamental na criação de uma experiência de usuário agradável. Com os componentes disponíveis no Android* SDK, a tarefa de depurar problemas de desempenho é facilitada pela simplicidade na utilização de ferramentas de análise de desempenho. Neste artigo, vamos olhar para as diferentes ferramentas disponíveis para depurar e solucionar problemas de desempenho ou conseguir um desempenho um pouco melhor em um aplicativo completo. Não entraremos em muitos detalhes, mas adotaremos uma abordagem de alto nível sobre como essas ferramentas podem ser utilizadas no seu aplicativo.

Demonstraremos as ferramentas de dentro do Eclipse; você pode instalar o plugin ADT seguindo as instruções no artigo  ADT Plugin for Eclipse*.

DDMS

DDMS é um aplicativo fornecido pelo Google* que funciona como uma ferramenta autônoma e também vem integrado ao Eclipse* através do plugin ADT Eclipse*. Ele fornece alguns recursos importantes que rapidamente lhe darão uma idéia de onde seu aplicativo está desperdiçando seu tempo.

Atualizações de threads

O monitor de threads e visão de perfil no DDMS é útil para aplicativos que gerenciam uma grande quantidade de threads. Para habilitá-lo, clique no ícone “Update Threads” (Atualizar threads) para iniciar.



Figura 1

Ele ativa a janela mostrada abaixo, que exibe nomes e alguns outros detalhes sobre todas as threads do processo de VM selecionado.



Figura 2

utime e stime representam o tempo total gasto por essa thread na execução do código do usuário (utime) e o sistema de código (stime) em "jiffies". A duração de um jiffy é definida pelo sistema, mas é comum um valor de 10ms. O asterisco indica uma daemon thread, o status native significa que a subrotina está executando código nativo. Olhando mais de perto os dados do exemplo acima, fica evidente que, além de a thread principal do aplicativo consumir uma quantidade significativa de tempo, uma quantidade não usual de tempo também está sendo gasta na execução de GC. Um olhar mais atento em como o aplicativo está tratando a criação do objeto pode ser uma boa idéia para melhorar o desempenho.

Ferramentas de heap

Visão de heap

Clique no botãoAtualização de heap para obter informações sobre as alocações de memória na VM (máquina virtual) selecionada.



Figura 3



Figura 4

Clique em "Cause GC" para começar. Os detalhes do heap são apresentados junto com um gráfico com os tamanhos de alocação para um tipo de alocação particular. Se houver um esvaziamento de alocação, este poderá ser um bom lugar para começar a procurar, verificar a tendência geral no tamanho do heap para se certificar de que não continuará a crescer indefinidamente durante a execução do aplicativo.

Rastreador de alocação

O próximo nível de detalhe sobre alocações é mostrado na visão “Allocation Tracker” (Rastreador de Alocação). Clique em "Start Tracking" (Iniciar rastreamento), execute uma ação no aplicativo e clique em "Get Allocations” (Obter alocações).



Figura 5

A lista apresentada está em ordem de alocação, com a atribuição mais recente aparecendo em primeiro lugar. Selecionando-a, você obterá um stack trace sobre como a alocação foi criada.

Olhando mais de perto os detalhes de alocação, verifica-se que o código a seguir tem espaço para melhorias:

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

A refatoração , como o código abaixo, é simples e evita a sobrecarga inerente à construção de um vetor de charcteres (char[]) temporário.

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

Profiling de método

Profiling de método é uma ferramenta dentro do DDMS útil para se obter uma visão geral rápida de onde o tempo está sendo gasto em seu aplicativo e que também pode ser utilizada para uma inspeção mais detalhada em funções urgentes.



Figura 6

Com o aplicativo em execução e, de preferência, realizando alguma tarefa interessante para se obter mais dados sobre seu desempenho, clique em "Start Method Profiling". O profiler coletará apenas uma pequena quantidade de dados (por não mais do que 2 ou 3 segundos), portanto, após alguns instantes, clique no ícone novamente para encerrar a coleta. Ativar o “profiling method” de dentro do DDMS faz com que a ferramenta utilize automaticamente o armazenamento interno para armazenar os resultados de perfil e, quando a captura estiver completa, enviará os resultados de volta ao host para análise posterior.

A IDE abrirá automaticamente a janela “Traceview”, que permite a você analisar os resultados à direita, dentro da IDE (Figura 7).



Figura 7

A interpretação dos resultados é a parte mais interessante. Clicando nas chamadas de método no painel inferior é criada uma hierarquia mostrando o método atual, o(s) pai(s) que chama(m) esse método e, em seguida, os métodos filhos chamados de dentro do método selecionado.

Neste aplicativo em teste selecionei o método onSensorChanged. Este é o método chamado pela API SensorManager quando você se registra para receber notificações de um tipo de sensor. A chamada do método aqui é handleMessage e vem do sistema operacional, então, começar com o meu método de implementação é um bom ponto a ser focado. Os métodos filhos são ordenados pelo percentual de tempo gasto "Inclusive" do método. “Inclusive” aqui indica o tempo gasto dentro desse método e todas as chamadas dos métodos filhos desse método. Assim, para a chamada onSensorChanged, mais de 70% do tempo foi gasto em calcStandardDeviation e averageSamples e eu poderia esperar a chamada para calcular um desvio padrão para uma quantidade mais significativa de tempo do que apenas as amostras médias, então, com esta nova informação eu poderia prosseguir e olhar mais detalhadamente a implementação e identificar as possíveis otimizações de código.


Para uma explicação mais detalhada de “Traceview”, confira o artigo Profiling with Traceview and dmtracedump

API para profiling

Para capturar detalhes de profiling de método com mais precisão, as chamadas para iniciar e parar o profiling podem ser feitas no código. Para utilizar este método, você precisará ter um cartão SD instalado no dispositivo. Abaixo está um exemplo de como adicionar “ganchos” para ter uma idéia melhor a respeito do meu código de manipulação de sensor:

	private static boolean doOnce = true;
	
	@Override
	public void onSensorChanged(SensorEvent event) {
		
		if ( doOnce ) {
			android.os.Debug.startMethodTracing();
		}
		
		Code under test…

		if ( doOnce ){
			android.os.Debug.stopMethodTracing();
			doOnce = false;
		}
	}
O arquivo de rastreamento está predefinido em /mnt/sdcard/dmtrace.trace e pode ser obtido de dentro do dispositivo com:

adb pull /mnt/sdcard/dmtrace.trace.

Execute a ferramenta “Traceview” "traceview C: \ dmtrace.trace" e ela iniciará uma interface de usuário semelhante àquela incorporada no Eclipse.

Ferramentas de Layout de UI

layoutopt

Sempre que estou próximo de concluir um aplicativo gosto de olhar para os ganhos de desempenho no layout de UI das atividades. A ferramenta layoutopt analisará os arquivos de layout e apontará possíveis problemas de desempenho. Isto está sendo tratado neste blogdocumento de referência. Vamos dar uma rápida olhada em como utilizar a ferramenta. O uso de linha de comando é parecido com este:

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

Nota: Coloquei o diretório das ferramentas do Android* SDK no meu caminho. Também parece que a ferramenta só funciona quando você especifica o caminho completo do diretório que deseja analisar.

Um exemplo de saída:

C:\Projects\workspace\DeviceInformation\res\drawable\btn_notification_ic_example.xml
C:\Projects\workspace\DeviceInformation\res\drawable\picture_frame.xml
C:\Projects\workspace\DeviceInformation\res\layout\action_bar_custom.xml
23:23 This TextView layout or its LinearLayout parent is useless
C:\Projects\workspace\DeviceInformation\res\layout\content_applicationinfo_main.xml
16:19 This LinearLayout layout or its LinearLayout parent is useless
C:\Projects\workspace\DeviceInformation\res\layout\content_benchmark_main.xml
C:\Projects\workspace\DeviceInformation\res\layout\content_main.xml
C:\Projects\workspace\DeviceInformation\res\layout\content_sensorinfo_main.xml
17:20 This LinearLayout layout or its LinearLayout parent is useless
O X:Y é a linha inicial e final das tags XML correspondentes à questão. Os layouts supérfluos apontados acima aumentam o tempo de carga total da atividade e são uma maneira fácil de tornar sua atividade de carga um pouco mais rápida.

Visualizador de hierarquia

Outra ferramenta útil na depuração de problemas de desempenho em layouts é a ferramenta Hierarchy Viewer. Este aplicativo só irá se conectar a uma versão de desenvolvedor do Android* OS, assim, sem acesso a um dispositivo de desenvolvimento a maneira mais fácil de utilizá-lo é com o emulador. Execute a ferramenta de linha de comando:

hierarchyviewer

Conclusão

Espero ter passado algumas novas ferramentas e algum conhecimento na sua busca por melhorar o desempenho dos aplicativos. Além de utilizar estas ferramentas para ver aonde você pode conseguir alguns ganhos, muitas melhorias de desempenho podem ser feitas no nível do código. O artigo Projetando para a desempenho é um ótimo lugar para aprender mais sobre algumas das técnicas comuns de codificação para melhor desempenho.

Aqui estão alguns artigos adicionais que incluem uma cobertura mais ampla e outras dicas e truques:

Designing for Responsiveness

Windows* Background & UI Speed

1http://help.eclipse.org/galileo/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/int_eclipse.htm

如需更全面地了解编译器优化,请参阅优化注意事项