Отладка производительности приложений для Android*

Обзор

Для того чтобы интерфейс понравился пользователю, приложение должно быстро реагировать на его действия. Пакет Android* SDK включает в себя удобные инструменты для анализа производительности, помогающие упростить отладку производительности в процессе разработки приложений. В этой статье рассмотрены различные инструменты, с помощью которых можно диагностировать проблемы и отлаживать производительность либо просто добиваться некоторого прироста производительности для уже готовых приложений. Здесь нет подробного описания работы, но даются общие сведения о том, как можно использовать эти инструменты для отладки Вашего приложения.

Работа с инструментами будет продемонстрирована в среде Eclipse; информацию об установке подключаемого модуля ADT можно найти в статье ADT Plugin for Eclipse*.
 

DDMS

DDMS - это программа от компании Google*, которую можно использовать как самостоятельный инструмент или в составе среды разработки Eclipse* при подключении модуля ADT для Eclipse*. Она включает в себя несколько интересных функций, позволяющих быстро понять чем занято Ваше приложение, когда его работа замедляется.
 

Обновление потоков

Для приложений, управляющих большим числом потоков, будет полезен экран мониторинга потоков и профилирования, доступный в программе DDMS. Чтобы открыть его, щелкните значок "Update Threads" (Обновить потоки).



Рис. 1

Открывается показанное ниже окно с именами и некоторыми другими сведениями обо всех потоках для выбранного процесса виртуальной машины.



Рис. 2

В столбцах utime и stime показано общее время, затраченное в этом потоке на выполнение пользовательского кода (utime) и системного кода (stime), в единицах измерения jiffy. Длительность jiffy определяется системой и обычно составляет 10 мс. Звездочкой отмечены потоковые демоны; статус "native" означает, что поток исполняет собственный код. В этом примере видно, что помимо главного потока приложения, потребляющего основное время, необычно много времени тратится на сборку мусора (поток GC). Если попытаться разобраться с тем, как приложение обрабатывает создание объектов, возможно, удастся повысить производительность.
 

Инструменты для работы с динамической памятью

Экран динамической памяти

Нажмите кнопку "Update Heap" (Обновить динамическую память), чтобы получить информацию о распределениях динамической памяти в выбранной виртуальной машине.



Рис. 3



Рис. 4

Нажмите кнопку "Cause GC" (Запустить сборку мусора). Отображаются подробные сведения о содержимом динамической памяти и диаграмма размеров распределений по каждому типу распределения. Если Вы заметите утечку памяти, следует обратить более пристальное внимание на эту ситуацию и проверить общую тенденцию изменения размера динамической памяти, чтобы выяснить, не начнет ли он бесконтрольно увеличиваться во время выполнения приложения.

Отслеживание распределений

Следующий уровень детализации распределений памяти показан на экране "Allocation Tracker" (Отслеживание распределений). Нажмите кнопку "Start Tracking" (Начать отслеживание), выполните требуемое действие в приложении и затем нажмите кнопку "Get Allocations" (Получить распределения).



Рис. 5

Отображаемый список распределений упорядочен по времени (вверху отображаются самые последние распределения). При выделении строки распределения отображается история его создания из трассировки стека.

При внимательном изучении сведений о распределении выясняется, что следующий код нуждается в оптимизации:

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

Можно реорганизовать код в нечто похожее на следующий пример - это поможет упростить выполнение и избежать дополнительной нагрузки, связанной с созданием временного массива char[].

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

 

 

Профилирование методов

Инструмент профилирования методов, включенный в программу DDMS, помогает быстро понять, на что тратится время в приложении, и позволяет подробно изучать работу функций, выполнение которых должно быть строго ограничено по времени.



Рис. 6

Запустите свое приложение и в момент идеального выполнения интересующей задачи, для которой требуется собрать дополнительные данные о производительности, щелкните значок "Start Method Profiling" (Начать профилирование метода). Средство профилирования собирает только небольшое количество данных (обычно не более чем за 2–3 секунды), поэтому через несколько секунд снова щелкните значок, чтобы остановить сбор данных. Если инструмент профилирования методов запускается из программы DDMS, он автоматически сохраняет результаты профилирования во внутреннюю память и после завершения захвата данных отправляет их в хост-систему для последующего анализа.

IDE автоматически запускает окно инструмента Traceview и позволяет анализировать результаты непосредственно в IDE (рис. 7).



Рис. 7

Самая интересная часть работы - это интерпретация результатов. Если щелкнуть вызов метода, в нижней части окна открывается иерархия, показывающая текущий метод, родительские методы, из которых вызывается данный метод, и дочерние методы, вызываемые из выбранного метода.

В тестируемом приложении выбран метод onSensorChanged. Этот метод вызывается из API-интерфейса SensorManager при регистрации для получения уведомления от сенсора. Вызывающим методом в данном случае является метод handleMessage, выполняемый в операционной системе, и мы можем легко определить его, начав со своего метода. Дочерние методы указаны в порядке убывания процента времени, в течение которого они были задействованы. Методы считаются задействованными в течение всего времени, пока выполняются они сами или их дочерние методы. Итак, при вызове метода onSensorChanged, более 70 % времени было потрачено на выполнение методов calcStandardDeviation и averageSamples. Можно предположить, что для вычисления стандартного отклонения потребуется больше времени, чем просто для усреднения элементов выборки, и на основании этой новой информации можно внимательнее присмотреться к реализации метода и попытаться оптимизировать его код.

Более подробное описание инструмента Traceview можно найти в статье Профилирование с помощью инструментов Traceview и dmtracedump

 

 

 

 

Профилирование через API

Для более точного захвата информации при профилировании метода можно включить вызовы запуска и остановки профилирования непосредственно в код. Чтобы воспользоваться этим способом, необходимо установить в устройстве SD-карту. Далее приведен пример добавления ловушек, которые помогут лучше понять работу нашего кода, обрабатывающего уведомления от сенсора:

 

 

 

 

	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;
		}
	}

Файл трассировки по умолчанию сохраняется по адресу /mnt/sdcard/dmtrace.trace, и его можно получить с устройства с помощью следующей команды:

adb pull /mnt/sdcard/dmtrace.trace.

Запустите инструмент Traceview в автономном режиме с помощью команды "traceview C:\dmtrace.trace"; откроется окно, аналогичное встроенному в Eclipse.

 

 

 

 

Инструменты для проверки компоновки пользовательского интерфейса

Инструмент layoutopt

Прежде чем завершить работу над приложением, я всегда проверяю, нет ли простых возможностей для повышения производительности за счет изменения компоновки пользовательского интерфейса. Инструмент layoutopt позволяет проанализировать файлы компоновки и найти потенциальные проблемы, влияющие на производительность. Можно ознакомиться с блогом и справочным документом, где этот инструмент описан более подробно, а в данной статье мы просто кратко продемонстрируем его использование. Командная строка выглядит следующим образом:

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

Примечание. Каталог инструментов Android* SDK помещен в нужную мне папку. Кроме того, похоже, что инструмент работает только при указании полного пути к каталогу, который необходимо проанализировать.

Пример выходных данных:

 

 

 

 

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

Значения Х:Y показывают начальную и конечную строки XML-тегов, относящихся к проблеме. Лишние элементы компоновки, отмеченные выше, увеличивают общее время загрузки при выполнении функций, то есть, если просто их убрать, функции будут загружаться немного быстрее.

 

 

 

 

Средство просмотра иерархии

При отладке проблем с производительностью, связанных с компоновкой, также может пригодиться средство просмотра иерархии. Это приложение можно подключить только к версии операционной системы Android* для разработчиков, поэтому при отсутствии устройства на стадии его разработки проще всего использовать это приложение с эмулятором. Для запуска инструмента введите в командной строке следующую команду:

 

 

 

 

hierarchyviewer

 

 

Заключение

Надеюсь, что представленная здесь информация о новых инструментах и приемах поможет Вам создавать приложения с более высокой производительностью. С помощью этих инструментов можно находить потенциальные возможности для повышения производительности на уровне кода. Дополнительную информацию о распространенных способах повышения производительности кода можно найти в статье о разработке, ориентированной на высокую производительность.

Далее указаны дополнительные статьи, содержащие более подробное описание и другие советы и рекомендации:

Разработка, ориентированная на высокую скорость отклика

Фоновые окна и скорость отрисовки пользовательского интерфейса

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