# Отладка и профилирование

Copyright&nbsp;©&nbsp;2016–2023 ООО&nbsp;«Открытая мобильная платформа».
Этот документ предоставляется в&nbsp;соответствии
с&nbsp;[Публичной лицензией Creative Commons с&nbsp;указанием авторства версии&nbsp;4.0 Международная](../../LICENSE.CC-BY-4.0.ru.md).

## Qt QmlLive — обновление приложения без пересборки

1.	Активировать Qt QmlLive для проекта Проекты → <цель> → Запуск → Enable receiving updates with Qt QmlLive
2.	Запустить приложение

При использовании на устройстве нужен пакет qmllive-sailfish

## Подключение внешнего устройства

Аврора SDK также может развернуть приложение на устройстве.
Для этой функции требуется, чтобы устройство было настроено с подключением USB или WLAN
к компьютеру и на нём был установлен пароль для работы через SSH.
Пароль задаётся на устройстве Настройки→Средства разработчика.
Для запуска приложения на устройстве в SDK необходимо выбрать подходящие параметры сборки.

Установка устройства осуществляется с помощью настроек IDE.
Это можно найти в меню «Инструменты» → «Параметры» → «Устройства».
В этом окне настроек нажмите «Добавить ...», чтобы начать создание настроек устройства.
Далее вы сможете дополнительно настроить конфигурацию соединения либо оставить конфигурацию по умолчанию.

## Работа со средой сборки из консоли

SDK установил общие папки для среды сборки и компьютера разработчика таким образом,
чтобы ваш домашний каталог был виден внутри среды сборки.
Вы можете найти его в каталоге /home/src1.
Первый шаг при запуске сборки — это войти в директорию своего проекта.

Там вы можете создать пакеты для эмуляторов и устройств.

После завершения сборки вы можете найти пакеты RPM в каталоге RPMS.
Если вы хотите создать свой проект вручную, просто сверните свои собственные команды сборки с помощью sb2.

Настоятельно рекомендуется развертывать приложение только на эмуляторе или устройстве в виде пакета RPM.

## Работа с эмулятором из консоли

Чтобы передать RPM эмулятору, выполните следующие команды.

1.	Скопировать пакет.
2.	Авторизоваться как пользователь root.
3.	Установить RPM.

Это приведет к появлению значка приложения в меню.

## Работа с устройством из консоли

На слайде приведены аналогичные команды для устройства.

## функциональность отладчика
 
 В Qt Creator имеется графический интерфейс для работы с отладчиком GDB.
 Он позволяет указывать точки останова, отлаживать программу построчно, прерывать работу приложения,
 просматривать содержимое стека вызовов, локальных и глобальных переменных и т. д.

Вы можете использовать режим отладки Qt Creator для проверки состояния вашего приложения.
Основная функциональность, которую отладчик предоставляет:

*	Проход через программу пошагово или построчно.
*	Прерывание запущенных программ.
*	Установка точек останова.
*	Вывод стека вызовов.
*	Вывод и изменение содержимого локальных и глобальных переменных.
*	Вывод и изменение регистров и содержимого памяти отлаженной программы.
*	Вывод списка загруженных разделяемых библиотек.
*	Дизассемблирование кода.
*	Создание моментальных снимков текущего состояния отлаживаемой программы (snapshots).

## Отладка приложений с изоляцией

Отладчик gdb можно подключить к приложению по номеру процесса, например, через консоль
или переконфигурацию gdb из Аврора IDE и двустороннюю передачу данных между gdb и Аврора IDE.

При запуске приложений из Аврора IDE с конфигурацией по умолчанию отладчик gdb не будет работать,
так как не будет запущена утилита sailjail, необходимая для отладки.

Для старта sailjail нужно запустить уже установленное приложение на устройстве
или на эмуляторе через значок.

Отладку можно выполнить следующим образом:

1.	Запустить приложение в песочнице, используя sailjail или firejail.
2.	Изменить у приложения конфигурацию по умолчанию в разделе Проекты → Запуск:
		полю Сменить программу на устройстве задать значение /usr/bin/sailjail, предварительно поставив галочку
		Использовать эту команду напротив поля;
	Сменить программу на устройстве
		полю Параметры командной строки задать значение -p <имя приложения>.desktop /usr/bin/<имя приложения>.
	Данный способ ориентирован на физическое устройство, sailjail не применяется на эмуляторе.
3.	Для отладки qml-кода нужно указать firejail вместо sailjail.
4.	Получить pid приложения.
5.	И подключить gdb к процессу, используя pid.

## После остановки программы

Как только программа остановится, среда разработки:

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

## Настройка точек останова

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

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

Вы можете установить и удалить контрольные точки до запуска программы или во время ее запуска
под управлением отладчика.
Точки останова сохраняются вместе с сеансом.

Чтобы добавить точку останова, в редакторе кода щелкните слева от строки или нажмите
F9 на определенной строке.
Слева от строки появится изображение точки останова.
В её контекстном меню можно деактивировать, убрать точку, а также вызвать диалог для изменения.
В диалоге вы можете задать условие останова, число пропусков и другие параметры.
Панель с точками останова отображается в режиме отладки по умолчанию снизу справа,
из его контекстного меню также можно управлять точками.

## Отладчик gdb: основные команды [1]

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

Основные команды:

*	run (r) начинает исполнение программы до первой точки останова или возникновения ошибки.
*	continue (c) продолжает выполнение программы до следующей точки останова или возникновения ошибки.
*	step (s) продолжает выполнение программы, пока оно не дойдёт до следующей строки исходного кода.
	При этом происходит вход в функцию, т. е. при вызове каждой функции программа также останавливается.
*	next (n) работает аналогично команде step, но при этом функции вызываются без остановки.
*	finish продолжает выполнение программы до возврата из текущей функции и печатает возвращаемое значение.

Командам step и next можно передать числовой параметр, который будет означать выполнение команды
заданное число раз.

## Отладчик gdb: основные команды [2]

Точки останова:

В произвольном месте программы можно поставить точку останова, при достижении которой
команда остановится.
При этом можно исследовать значения переменных, продолжить выполнение программы при помощи
команд c, s, n или выполнить другие команды GDB.

*	break n (b) устанавливает точку останова на строке исходного кода с номером n.
	Все точки останова имеют свои номера, определяемые при их установке.
*	break function устанавливает точку останова на функции function.
	Исполнение программы остановится при вызове этой функции.
	Распространенный пример: break main для того, чтобы можно было пошагово исполнять программу
	с самого начала.
*	clear n  удаляет точку останова в строке с номером n.
*	delete диапазон (d) удаляет точки останова с номерами из указанного диапазона.
	Например, delete 1-5 или delete 4.
	Если диапазон не задан, удаляются все точки останова.

Просмотр исходного кода и стека программы.

Для вывода исходного текста программы используется команда list (l):

*	list n выводит строки исходного кода вокруг строки с номером n.

Работа с кадром стека:

*	where выводит содержимое стека.
*	frame n  переключается в кадр с номером n.
*	info locals выводит информацию о всех локальных переменных текущего кадра.

Исследование выражений.

Для исследования данных обычно используется команда print (p) или ее синоним inspect.

*	print выраж  вычисляет и выводит значение выражения, записанного на том же языке, что и ваша программа.

## Профилирование

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

Это часто используется, чтобы определить, как долго выполняются определенные части программы,
как часто они выполняются, или генерировать граф вызовов (Call Graph).
Обычно эта информация используется, чтобы идентифицировать те участки программы, которые работают
больше всего.
Эти трудоёмкие участки могут быть оптимизированы, чтобы выполняться быстрее.

## Инструменты анализа кода Valgrind

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

Вы можете запускать инструменты Valgrind локально на хосте разработки или удаленно на другом хосте.
Вы можете использовать их для анализа как приложений, для которых вы создали проект в IDE,
так и приложений, для которых у вас нет проекта.

Инструменты Valgrind локально поддерживаются только в Linux и macOS.
Тем не менее, согласно Valgrind.org, поддержка macOS 10.8 и 10.9 является экспериментальной
и в основном не работает.
Вы можете запускать инструменты на удаленной машине или устройстве Linux с любого хоста разработки.

В дистрибутив Valgrind входят следующие инструменты отладки и профилирования:

*	Memcheck
*	Callgrind

## Memcheck

Memcheck обнаруживает проблемы с управлением памятью и нацелен прежде всего на программы на C и C ++.
Когда программа запускается под наблюдением Memcheck, все чтения и записи памяти проверяются,
а вызовы malloc/new/free/ delete перехватываются.
В результате Memcheck может обнаружить, если ваша программа:

*	Получает доступ к памяти, которой не должна (области еще не выделены, области, которые были
	освобождены, области после конца блоков кучи, недоступные области стека).
*	Использует неинициализированные значения опасными способами.
*	Имеет утечки памяти.
*	Осуществляет плохие освобождения блоков кучи (двойные освобождения, несовпадающие освобождения).
*	Передает перекрывающиеся блоки памяти источника и назначения в memcpy() и связанные функции.

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

## Memcheck: анализ приложений

Для анализа приложений:

1.	Выбрать тип сборки Профилирование.
2.	Переключить Аврора IDE в режим Проекты.
3.	Выбрать пункт Запуск для таргета.
4.	В разделе Запуск в выпадающем списке Конфигурация запуска добавить конфигурацию
	ru.auroraos.TestAppName (on %{Device:Name}).
	Где ru.auroraos.TestAppName — имя приложения, которое нужно протестировать.
	Данная конфигурация приложения в указанных в данном пункте параметрах совпадает с конфигурацией
	по умолчанию, тем не менее рекомендуется создать новую, чтобы можно было легко переключаться
	между обычным запуском приложения и запуском в режиме профилирования.
5.	Активировать поле Сменить программу на устройстве с помощью галочки и и указать valgrind в поле Использовать эту команду .
6.	В поле Параметры командной строки указать параметры.
7.	Запустить приложение из IDE в режиме профилирования с помощью кнопки запуска приложения.

Выполнить в приложении задуманный сценарий и завершить работу приложения.
Производительность приложения во время профилирования, как правило, существенно снижается.
По окончании работы приложения профайлер создаст в домашней директории файл
с результатами профилирования.
Имя файла соответствует значению, указанному в параметре --xml-file .

## Callgrind: профилирование

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

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

## Callgrind: анализ приложений

Для анализа приложений:

1.	Открыть меню Анализ и выбрать пункт Профайлер функций Valgrind (внешняя программа).
2.	В открывшемся диалоге заполнить поля данными:
	Выбрать комплект сборки.
	В поле Программа указать название приложения. Например, ru.auroraos.TestApp.
	Название приложения должно соответствовать значению Name из файла .spec.
	В поле Параметры указать передаваемые приложению параметры, при необходимости.
3.	Нажать ОК. Приложение будет запущено.
4.	Выполнить в приложении задуманный сценарий и завершить работу приложения.
	По окончании работы приложения профайлер создаст файл с результатами профилирования
	в домашней директории.
	Файл callgrind.out.*, где * — число, добавленное программой для уникальности названия.

## Callgrind: просмотр результатов

Перед просмотром результатов профилирования необходимо перенести файл callgrind.out.*
в систему разработчика, где ведётся работа над проектом (см. шаг 4 Профилирование функций).

Для просмотра результатов следует выполнить следующие шаги:

1.	Переключить IDE в режим Отладка.
2.	Выбрать Callgrind в выпадающем списке панели отладки.
3.	Нажать на  и выбрать файл с результатом профилирования callgrind.out.*.

## Профилирование QML-приложений

Для поиска типичных проблем производительности приложения, например, медлительность
пользовательского интерфейса, можно использовать QML-профайлер.

К причинам снижения скорости работы пользовательского интерфейса можно отнести:

*	Выполнение большого количества JavaScript-кода при малом количестве кадров.
	Весь JavaScript-код должен завершиться прежде, чем GUI-поток сможет продолжить работу.
	Если GUI-поток не готов, то кадры задерживаются или отбрасываются.
*	Создание, отрисовка или обновление невидимых элементов, которые также занимают время в GUI-потоке.

Для поиска чрезмерного использования JavaScript-кода, следует проверить частоту кадров в анимациях
и событиях Scene Graph, найти разрывы и проверить, ведёт ли себя приложение так, как задумано.
Категория событий JavaScript в QML-профайлере отображает время выполнения функций,
которое рекомендуется держать ниже 16 мс на кадр.

Если кадры отбрасываются, когда JavaScript код не выполняется, и на временной шкале присутствуют
разрывы, то следует проверить реализацию пользовательского QQuickItem.

## Запуск QML-профайлера

QML-профайлер можно использовать как на эмуляторе, так и на устройстве.
Для работы с профайлером на устройстве требуется отключить валидатор.

Для отслеживания производительности приложения с помощью QML-профайлера
необходимо выполнить следующие шаги:

1.	Выбрать тип сборки Профилирование.
2.	Убедиться, что у проекта включена возможность QML-отладки (по умолчанию QML-отладка включена):
	Переключить Aurora IDE в режим Проекты.
	Выбрать пункт Сборка целевого комплекта.
	Убедиться, что в разделе Отладка и профилирование QML → Основное установлено значение Включить.
3.	Запустить профилирование в меню Анализ, выбрав пункт Профайлер QML.

## Утилита strace

strace – утилита отслеживает системные вызовы и сигналы.

В простейшем случае strace запускает указанную команду до ее выхода.
Он перехватывает и записывает системные вызовы, вызываемые процессом, и сигналы,
принимаемые процессом.
Имя каждого системного вызова, его аргументы и возвращаемое значение выводятся
по стандартному пути вывода ошибок или в файл, указанный с помощью опции -o.

strace — полезный инструмент диагностики, обучения и отладки.

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

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

## Опции Strace: Статистика

*	-c Подсчитывать время, вызовы и ошибки для каждого системного вызова и сообщать сводные данные
	о выходе из программы, подавляя обычный вывод.
	Команда пытается показать системное время (процессорное время, потраченное на работу в ядре)
	независимо от времени настенных часов.
	Если -c используется с -f, сохраняются только совокупные итоги для всех отслеживаемых процессов.
*	-S sortby Сортировать выходные данные гистограммы, напечатанной параметром -c, по указанному критерию.
	Допустимые значения: время, вызовы, имя и ничего (по умолчанию время).
*	-w Суммируйте разницу во времени между началом и концом каждого системного вызова.
	По умолчанию суммируется системное время.

Фильтрация

*	-e expr Уточняющее выражение, которое изменяет, какие события отслеживать или как их отслеживать.

## Strace: Диагностика

При выходе из команды strace выходит с тем же статусом выхода, что и команда.
Если команда завершается сигналом, strace завершает себя тем же сигналом, так что strace может
использоваться как процесс-обертка, прозрачный для вызывающего родительского процесса.
Обратите внимание, что отношения родитель-потомок (уведомления о прекращении сигнала,
значение getppid () и т. д.) между отслеживаемым процессом и его родителем не сохраняются,
если не используется -D.

При использовании -p без команды состояние выхода strace равно нулю, если не было присоединено
ни одного процесса или произошла непредвиденная ошибка при выполнении трассировки.
