10.3 Использование gcov с оптимизацией GCC
Если вы планируете использовать gcov для оптимизации своего кода, вы должны сначала скомпилировать свою программу с использованием специального параметра GCC ‘--coverage’. Помимо этого, вы можете использовать любые другие параметры GCC; но если вы хотите убедиться, что каждая строка в вашей программе была выполнена, вы не должны компилировать с оптимизацией одновременно. На некоторых машинах оптимизатор может исключить некоторые простые строки кода, объединив их с другими строками. Например, код такого вида:
if (a != b) c = 1; else c = 0;
может быть скомпилирован в одну инструкцию на некоторых машинах. В этом случае gcov не может вычислить отдельные счетчики выполнения для каждой строки, потому что для каждой строки нет отдельного кода. Поэтому вывод gcov выглядит следующим образом, если вы скомпилировали программу с оптимизацией:
100: 12:if (a != b) 100: 13: c = 1; 100: 14:else 100: 15: c = 0;
Вывод показывает, что этот блок кода, объединенный оптимизацией, был выполнен 100 раз. В некотором смысле этот результат верен, потому что была только одна инструкция, представляющая все четыре строки. Однако вывод не указывает, сколько раз результат был равен 0 и сколько раз результат был равен 1.
Встраиваемые функции могут создавать неожиданные счетчики строк. Счетчики строк отображаются для исходного кода встраиваемой функции, но то, что отображается, зависит от того, где функция встраивается, или если она вообще не встраивается.
Если функция не встраивается, компилятор должен выдать внестрочную копию функции в любом объектном файле, который её нуждается. Если fileA.o и fileB.o оба содержат внестрочные тела определенной встраиваемой функции, они также будут оба содержать счетчики покрытия для этой функции. Когда fileA.o и fileB.o связываются вместе, компоновщик на многих системах выберет одно из этих внестрочных тел для всех вызовов этой функции и удалит или проигнорирует другие. К сожалению, он не удалит счетчики покрытия для неиспользуемого тела функции. Таким образом, при инструментировании все, кроме одного использования этой функции, будут показывать нулевые счетчики.
Если функция встраивается в нескольких местах, структура блока в каждом месте может быть разной. Например, условие может быть вычислено на этапе компиляции в некоторых случаях. Поскольку покрытие всех применений встраиваемой функции будет отображаться для одних и тех же строк исходного кода, сами счетчики строк могут показаться несогласованными.
Приложения с длительным выполнением могут использовать средства __gcov_reset и __gcov_dump для ограничения сбора профиля областью программы, представляющей интерес. Вызов __gcov_reset(void) обнулит все счетчики профиля, а вызов __gcov_dump(void) приведет к тому, что информация о профиле, собранная в этот момент, будет выгружена в выходные файлы .gcda. Инструментированные приложения используют статический деструктор с приоритетом 99 для вызова функции __gcov_dump. Таким образом, __gcov_dump выполняется после всех пользовательских статических деструкторов, а также обработчиков, зарегистрированных с помощью atexit. Если исполняемый файл загружает динамическую общую библиотеку через функцию dlopen, необходимо использовать -Wl,--dynamic-list-data, чтобы выгрузить все данные профиля.
Отчеты о профилировании времени выполнения библиотеки сообщают об различных ошибках, связанных с манипулированием профилем и сохранением профиля. Ошибки выводятся в стандартный поток ошибок или в файл ‘GCOV_ERROR_FILE’, если используется переменная среды. Для немедленного завершения после возникновения ошибки установите переменную среды ‘GCOV_EXIT_AT_ERROR’. Это может помочь пользователям найти конфликты профилей, которые приводят к вводящим в заблуждение профилям.
Далее: Файлы данных Gcov, Предыдущий: Вызов Gcov, Вверх: Gcov [Оглавление][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-9.5.0/gcc/Gcov-and-Optimization.html