10.3 Использование gcov с оптимизацией GCC
Если вы планируете использовать gcov для оптимизации кода, необходимо сначала скомпилировать программу с двумя специальными опциями GCC: ‘-fprofile-arcs -ftest-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, Предыдущий: Вызов Gcov, Вверх: Gcov [Оглавление][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-7.5.0/gcc/Gcov-and-Optimization.html