10.2 Вызов gcov
gcov [options] files
gcov принимает следующие параметры:
-a--all-blocks-
Записывает индивидуальные счётчики выполнения для каждого базового блока. Обычно gcov выводит счётчики выполнения только для основных блоков строки. С этим параметром вы можете определить, не выполняются ли блоки в одной строке.
-b--branch-probabilities-
Записывает частоты ветвлений в выходной файл и информацию о сводках ветвлений в стандартный вывод. Этот параметр позволяет увидеть, как часто брались каждая ветвь в вашей программе. Неусловные ветви не будут показаны, если не задан параметр -u.
-c--branch-counts-
Записывает частоты ветвлений как число выполненных ветвей, а не как процент выполненных ветвей.
-d--display-progress-
Отображает процесс в стандартном выводе.
-f--function-summaries-
Выводит сводки для каждой функции помимо сводки на уровне файла.
-h--help-
Отображает справку по использованию
gcov(в стандартном выводе) и завершает работу, не выполняя дальнейшей обработки. -j--json-format-
Выводит файл gcov в формате промежуточного JSON, который легко парсируется и не требует исходного кода для генерации. Файл JSON сжат алгоритмом gzip, и файлы имеют расширение .gcov.json.gz.
Структура JSON следующая:
{ "current_working_directory": "foo/bar", "data_file": "a.out", "format_version": "1", "gcc_version": "11.1.1 20210510" "files": ["$file"] }Поля корневого элемента имеют следующее семантическое значение:
- current_working_directory: рабочая директория, где был скомпилирован модуль
- data_file: имя файла данных (GCDA)
- format_version: семантическая версия формата
- gcc_version: версия компилятора GCC
Каждый элемент file имеет следующий вид:
{ "file": "a.c", "functions": ["$function"], "lines": ["$line"] }Поля элемента file имеют следующее семантическое значение:
- file_name: имя исходного файла
Каждый элемент function имеет следующий вид:
{ "blocks": 2, "blocks_executed": 2, "demangled_name": "foo", "end_column": 1, "end_line": 4, "execution_count": 1, "name": "foo", "start_column": 5, "start_line": 1 }Поля элемента function имеют следующее семантическое значение:
- blocks: количество блоков в функции
- blocks_executed: количество выполненных блоков функции
- demangled_name: разобранное имя функции
- end_column: столбец в исходном файле, где функция заканчивается
- end_line: строка в исходном файле, где функция заканчивается
- execution_count: количество выполнений функции
- name: имя функции
- start_column: столбец в исходном файле, где функция начинается
- start_line: строка в исходном файле, где функция начинается
Обратите внимание, что номера строк и столбцов начинаются с 1. В текущей реализации start_line и start_column не включают параметры шаблонов и тип возвращаемого значения, но, вероятно, это будет исправлено в будущем.
Каждый элемент line имеет следующий вид:
{ "branches": ["$branch"], "count": 2, "line_number": 15, "unexecuted_block": false, "function_name": "foo", }Ветви присутствуют только с параметром -b. Поля элемента line имеют следующее семантическое значение:
- count: количество выполнений строки
- line_number: номер строки
- unexecuted_block: флаг, указывающий, содержит ли строка невыполненный блок (не все операторы в строке выполнены)
- function_name: имя функции, к которой принадлежит эта строка (для строки с вложенными операторами может отсутствовать)
Каждый элемент branch имеет следующий вид:
{ "count": 11, "fallthrough": true, "throw": false }Поля элемента branch имеют следующее семантическое значение:
- count: количество выполнений ветви
- fallthrough: true, если ветвь является проходной
- throw: true, если ветвь является исключительной
-H--human-readable-
Записывает счётчики в удобочитаемом формате (например, 24.6k).
-k--use-colors-
Использует цвета для строк кода с нулевой покрываемостью. Мы используем красный цвет для обычных строк и циан для исключительных. Те же цвета используются для базовых блоков с параметром -a.
-l--long-file-names-
Создаёт длинные имена файлов для включённых исходных файлов. Например, если заголовочный файл x.h содержит код и был включён в файл a.c, то выполнение
gcovна файле a.c создаст выходной файл с именем a.c##x.h.gcov вместо x.h.gcov. Это может быть полезно, если x.h включён в несколько исходных файлов, и вы хотите видеть отдельные вклады. Если вы используете параметр ‘-p’, то имена как включающего, так и включаемого файла будут полными путями. -m--demangled-names-
Отображает разобранные имена функций в выводе. По умолчанию отображаются склеенные имена функций.
-n--no-output-
Не создаёт файл выходных данных
gcov. -o directory|file--object-directory directory--object-file file-
Указывает директорию, содержащую файлы данных gcov, или имя пути к объекту. Файлы данных .gcno и .gcda ищутся с использованием этого параметра. Если указана директория, файлы данных находятся в этой директории и имеют имя, соответствующее имени входного файла без расширения. Если указан файл, файлы данных имеют имя, соответствующее этому файлу без расширения.
-p--preserve-paths-
Сохраняет полную информацию о пути в именах сгенерированных файлов .gcov. Без этого параметра используется только имя файла. С этим параметром используются все директории, при этом символы ‘/’ заменяются на ‘#’, компоненты директорий . удаляются, а компоненты .. переименовываются в ‘^’. Это полезно, если исходные файлы находятся в нескольких различных директориях.
-q--use-hotness-colors-
Выводит цветной вывод в стиле perf для горячих строк. Легенда шкалы цветов печатается в самом начале выходного файла.
-r--relative-only-
Выводит только информацию о исходных файлах с относительным путем (после удаления префикса исходного файла). Абсолютные пути обычно соответствуют системным заголовочным файлам, и покрытие любых вложенных функций в них обычно не представляет интереса.
-s directory--source-prefix directory-
Префикс для имен исходных файлов, который нужно удалить при генерации выходных файлов покрытия. Этот параметр полезен при компиляции в отдельной директории, и путь к директории исходных файлов не требуется при определении имён выходных файлов. Обратите внимание, что обнаружение префикса применяется до определения абсолютности исходного файла.
-t--stdout-
Выводит данные в стандартный вывод вместо файлов вывода.
-u--unconditional-branches-
При наличии вероятностей ветвления включать вероятности безусловных ветвлений. Безусловные ветви обычно не представляют интереса.
-v--version-
Отображает номер версии
gcov(в стандартном выводе) и завершает работу, не выполняя дальнейшей обработки. -w--verbose-
Выводит подробную информацию о базовых блоках и дугах.
-x--hash-filenames-
При использовании –preserve-paths, gcov использует полный путь к исходным файлам для создания имени выходного файла. Это может привести к длинным именам файлов, которые могут превышать ограничения файловой системы. Этот параметр создаёт имена в формате source-file##md5.gcov, где source-file — конечная часть имени файла, а md5 — вычисленное значение по полному склеенному имени, которое использовалось бы в противном случае. Параметр является альтернативой –preserve-paths на системах с ограничением файловой системы.
gcov нужно запускать, имея текущую директорию такой же, как при вызове компилятора. В противном случае он не сможет найти исходные файлы. gcov создаёт файлы с именем mangledname.gcov в текущей директории. Они содержат информацию о покрытии соответствующего исходного файла. Один файл .gcov генерируется для каждого исходного (или заголовочного) файла, содержащего код, который был скомпилирован для получения файлов данных. Часть mangledname имени выходного файла обычно просто имя исходного файла, но может быть более сложной, если используются параметры ‘-l’ или ‘-p’. Подробности см. в описаниях этих параметров.
Если вы вызываете gcov с несколькими входными файлами, вклады из каждого входного файла суммируются. Обычно вы вызываете его с тем же списком файлов, что и при окончательной линковке вашего исполняемого файла.
Файлы .gcov содержат поля, разделённые двоеточиями, вместе с исходным кодом программы. Формат
execution_count:line_number:source line text
Дополнительная информация о блоке может следовать за каждой строкой по запросу опции командной строки. Значение execution_count равно ‘-’ для строк, не содержащих кода. Невыполненные строки помечены ‘#####’ или ‘=====’, в зависимости от того, доступны ли они по обычным путям выполнения или только по исключительным путям, таким как обработчики исключений C++, соответственно. При использовании опции ‘-a’, невыполненные блоки помечены ‘$$$$$’ или ‘%%%%%’, в зависимости от того, доступен ли базовый блок по обычным или исключительным путям. Выполненные базовые блоки, содержащие оператор с нулевым значением execution_count, завершаются символом ‘*’ и выделяются фиолетовым цветом с опцией -k. Эта функциональность не поддерживается в Ada.
Обратите внимание, что GCC может полностью удалить тела функций, которые не нужны — например, если они повсюду встроены. Такие функции помечены ‘-’, что может быть запутывающим. Используйте опции -fkeep-inline-functions и -fkeep-static-functions, чтобы сохранить эти функции и позволить gcov корректно отобразить их execution_count.
Некоторые строки информации в начале имеют line_number ноль. Эти строки преамбулы имеют вид
-:0:tag:value
Порядок и количество этих строк преамбулы будут дополнены по мере развития — не полагайтесь на их неизменность. Используйте tag для поиска конкретной строки преамбулы.
Дополнительная информация о блоке имеет вид
tag information
information — читабельная для человека информация, но достаточно простая для машинного анализа.
При выводе процентов 0% и 100% выводятся только тогда, когда значения точно равны 0% и 100% соответственно. Другие значения, которые обычно округляются до 0% или 100%, вместо этого выводятся как ближайшее значение, отличное от граничных.
При использовании gcov, необходимо сначала скомпилировать программу со специальной опцией GCC ‘--coverage’. Это сообщает компилятору о необходимости генерации дополнительной информации, необходимой gcov (по существу, графа потока программы), а также включает дополнительный код в объектные файлы для генерации дополнительной информации о профилировании, необходимой gcov. Эти дополнительные файлы помещаются в каталог, где расположен объектный файл.
Запуск программы приведет к генерации выходных данных профилирования. Для каждого исходного файла, скомпилированного с -fprofile-arcs, будет создан соответствующий файл .gcda в каталоге объектных файлов.
Запуск gcov с именами исходных файлов программы в качестве аргументов теперь выведет список кода вместе с частотой выполнения каждой строки. Например, если ваша программа называется tmp.cpp, вот что вы увидите при использовании базовой gcov возможности:
$ g++ --coverage tmp.cpp -c $ g++ --coverage tmp.o $ a.out $ gcov tmp.cpp -m File 'tmp.cpp' Lines executed:92.86% of 14 Creating 'tmp.cpp.gcov'
Файл tmp.cpp.gcov содержит вывод от gcov. Вот пример:
-: 0:Source:tmp.cpp
-: 0:Working directory:/home/gcc/testcase
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:template<class T>
-: 4:class Foo
-: 5:{
-: 6: public:
1*: 7: Foo(): b (1000) {}
------------------
Foo<char>::Foo():
#####: 7: Foo(): b (1000) {}
------------------
Foo<int>::Foo():
1: 7: Foo(): b (1000) {}
------------------
2*: 8: void inc () { b++; }
------------------
Foo<char>::inc():
#####: 8: void inc () { b++; }
------------------
Foo<int>::inc():
2: 8: void inc () { b++; }
------------------
-: 9:
-: 10: private:
-: 11: int b;
-: 12:};
-: 13:
-: 14:template class Foo<int>;
-: 15:template class Foo<char>;
-: 16:
-: 17:int
1: 18:main (void)
-: 19:{
-: 20: int i, total;
1: 21: Foo<int> counter;
-: 22:
1: 23: counter.inc();
1: 24: counter.inc();
1: 25: total = 0;
-: 26:
11: 27: for (i = 0; i < 10; i++)
10: 28: total += i;
-: 29:
1*: 30: int v = total > 100 ? 1 : 2;
-: 31:
1: 32: if (total != 45)
#####: 33: printf ("Failure\n");
-: 34: else
1: 35: printf ("Success\n");
1: 36: return 0;
-: 37:}
Обратите внимание, что строка 7 показана в отчете несколько раз. Первое появление показывает общее количество выполнений строки, а следующие два относятся к конструкторам экземпляров класса Foo. Как вы также можете видеть, строка 30 содержит некоторые невыполненные базовые блоки, поэтому счёт выполнения содержит звездочку.
При использовании опции -a, вы получите индивидуальные подсчёты блоков, и вывод будет выглядеть так:
-: 0:Source:tmp.cpp
-: 0:Working directory:/home/gcc/testcase
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:template<class T>
-: 4:class Foo
-: 5:{
-: 6: public:
1*: 7: Foo(): b (1000) {}
------------------
Foo<char>::Foo():
#####: 7: Foo(): b (1000) {}
------------------
Foo<int>::Foo():
1: 7: Foo(): b (1000) {}
------------------
2*: 8: void inc () { b++; }
------------------
Foo<char>::inc():
#####: 8: void inc () { b++; }
------------------
Foo<int>::inc():
2: 8: void inc () { b++; }
------------------
-: 9:
-: 10: private:
-: 11: int b;
-: 12:};
-: 13:
-: 14:template class Foo<int>;
-: 15:template class Foo<char>;
-: 16:
-: 17:int
1: 18:main (void)
-: 19:{
-: 20: int i, total;
1: 21: Foo<int> counter;
1: 21-block 0
-: 22:
1: 23: counter.inc();
1: 23-block 0
1: 24: counter.inc();
1: 24-block 0
1: 25: total = 0;
-: 26:
11: 27: for (i = 0; i < 10; i++)
1: 27-block 0
11: 27-block 1
10: 28: total += i;
10: 28-block 0
-: 29:
1*: 30: int v = total > 100 ? 1 : 2;
1: 30-block 0
%%%%%: 30-block 1
1: 30-block 2
-: 31:
1: 32: if (total != 45)
1: 32-block 0
#####: 33: printf ("Failure\n");
%%%%%: 33-block 0
-: 34: else
1: 35: printf ("Success\n");
1: 35-block 0
1: 36: return 0;
1: 36-block 0
-: 37:}
В этом режиме каждый базовый блок отображается только в одной строке — в последней строке блока. Многострочный блок будет учитываться только в счёт выполнения последней строки, а другие строки не будут отображать код, если предыдущие блоки не заканчиваются на этих строках. Общий счёт выполнения строки отображается, а последующие строки отображают счёт выполнения отдельных блоков, которые заканчиваются на этой строке. После каждого блока выводятся счёт ветвлений и вызовов блока, если задана опция -b.
Из-за того, как GCC обрабатывает вызовы, счёт вызовов может отображаться после строки без отдельных блоков. Как вы можете видеть, строка 33 содержит базовый блок, который не был выполнен.
При использовании опции -b ваш вывод будет выглядеть так:
-: 0:Source:tmp.cpp
-: 0:Working directory:/home/gcc/testcase
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:template<class T>
-: 4:class Foo
-: 5:{
-: 6: public:
1*: 7: Foo(): b (1000) {}
------------------
Foo<char>::Foo():
function Foo<char>::Foo() called 0 returned 0% blocks executed 0%
#####: 7: Foo(): b (1000) {}
------------------
Foo<int>::Foo():
function Foo<int>::Foo() called 1 returned 100% blocks executed 100%
1: 7: Foo(): b (1000) {}
------------------
2*: 8: void inc () { b++; }
------------------
Foo<char>::inc():
function Foo<char>::inc() called 0 returned 0% blocks executed 0%
#####: 8: void inc () { b++; }
------------------
Foo<int>::inc():
function Foo<int>::inc() called 2 returned 100% blocks executed 100%
2: 8: void inc () { b++; }
------------------
-: 9:
-: 10: private:
-: 11: int b;
-: 12:};
-: 13:
-: 14:template class Foo<int>;
-: 15:template class Foo<char>;
-: 16:
-: 17:int
function main called 1 returned 100% blocks executed 81%
1: 18:main (void)
-: 19:{
-: 20: int i, total;
1: 21: Foo<int> counter;
call 0 returned 100%
branch 1 taken 100% (fallthrough)
branch 2 taken 0% (throw)
-: 22:
1: 23: counter.inc();
call 0 returned 100%
branch 1 taken 100% (fallthrough)
branch 2 taken 0% (throw)
1: 24: counter.inc();
call 0 returned 100%
branch 1 taken 100% (fallthrough)
branch 2 taken 0% (throw)
1: 25: total = 0;
-: 26:
11: 27: for (i = 0; i < 10; i++)
branch 0 taken 91% (fallthrough)
branch 1 taken 9%
10: 28: total += i;
-: 29:
1*: 30: int v = total > 100 ? 1 : 2;
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
-: 31:
1: 32: if (total != 45)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
#####: 33: printf ("Failure\n");
call 0 never executed
branch 1 never executed
branch 2 never executed
-: 34: else
1: 35: printf ("Success\n");
call 0 returned 100%
branch 1 taken 100% (fallthrough)
branch 2 taken 0% (throw)
1: 36: return 0;
-: 37:}
Для каждой функции выводится строка, показывающая, сколько раз функция вызывалась, сколько раз она возвращалась и какой процент блоков функции был выполнен.
Для каждого базового блока после последней строки базового блока печатается строка, описывающая ветвление или вызов, который завершает базовый блок. Для одной строки исходного кода может быть указано несколько ветвлений и вызовов, если на этой строке заканчивается несколько базовых блоков. В этом случае ветвлениям и вызовам присваиваются номера. Нет простого способа сопоставить эти ветвления и вызовы с конструкциями исходного кода. Однако, как правило, ветвление или вызов с наименьшим номером будет соответствовать левой конструкции на строке исходного кода.
Для ветвления, если оно выполнилось хотя бы один раз, выводится процент, показывающий количество раз, когда ветвление было выбрано, поделённое на количество раз, когда ветвление было выполнено. В противном случае выводится сообщение «ни разу не выполнено».
Для вызова, если он выполнился хотя бы один раз, выводится процент, показывающий количество раз, когда вызов возвращался, поделённое на количество раз, когда вызов был выполнен. Это обычно будет 100%, но может быть меньше для функций, которые вызывают exit или longjmp, и, таким образом, могут не возвращаться каждый раз, когда вызываются.
Счёты выполнения являются кумулятивными. Если пример программы выполняется ещё раз без удаления файла .gcda, количество раз, когда каждая строка исходного кода выполнялась, добавляется к результатам предыдущего(их) запуска(ов). Это может быть полезно в нескольких аспектах. Например, это может быть использовано для накопления данных по множеству запусков программы в рамках набора тестов или для предоставления более точной долгосрочной информации по большому количеству запусков программы.
Данные в файлах .gcda сохраняются непосредственно перед завершением программы. Для каждого исходного файла, скомпилированного с опцией -fprofile-arcs, код профилирования сначала пытается прочитать существующий файл .gcda; если файл не соответствует исполняемому файлу (отличающееся количество базовых блоков), он игнорирует содержимое файла. Затем он добавляет новые счётчики выполнения и, наконец, записывает данные в файл.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-13.3.0/gcc/Invoking-Gcov.html