10.2 Вызов gcov
gcov [options] files
gcov принимает следующие параметры:
-a--all-blocks-
Записать индивидуальные счётчики выполнения для каждого базового блока. Обычно gcov выводит счётчики выполнения только для основных блоков строки. С этим параметром можно определить, если блоки внутри одной строки не выполняются.
-b--branch-probabilities-
Записать частоты ветвлений в выходной файл и информацию о сводке ветвлений в стандартный вывод. Этот параметр позволяет увидеть, как часто каждая ветвь в вашей программе была пройдена. Неусловные ветви не будут показаны, если не задан параметр -u.
-c--branch-counts-
Записать частоты ветвлений как количество пройденных ветвлений, а не как процент пройденных ветвлений.
-g--conditions-
Записать покрытие условий в выходной файл и информацию о сводке условий в стандартный вывод. Этот параметр позволяет увидеть, если условия в вашей программе хотя бы один раз имели независимое влияние на результат булевого выражения (модифицированное покрытие условий/решений). Для этого вам необходимо скомпилировать исходный код с параметром -fcondition-coverage.
-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": "2", "gcc_version": "11.1.1 20210510" "files": ["$file"] }Поля корневого элемента имеют следующий смысл:
- current_working_directory: рабочий каталог, в котором был скомпилирован блок компиляции
- data_file: имя файла данных (GCDA)
-
format_version: семантическая версия формата
Изменения в версии 2:
- calls: добавлена информация о вызовах функций
- 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 имеет следующий вид:
{ "block_ids": ["$block_id"], "branches": ["$branch"], "calls": ["$call"], "count": 2, "conditions": ["$condition"], "line_number": 15, "unexecuted_block": false, "function_name": "foo", }Ветви и вызовы присутствуют только с параметром -b. Поля элемента line имеют следующий смысл:
- block_ids: идентификаторы базовых блоков, принадлежащих строке
- count: количество выполнений строки
- line_number: номер строки
- unexecuted_block: флаг, указывающий, содержит ли строка невыполненный блок (не все операторы в строке выполнены)
- function_name: имя функции, к которой принадлежит эта строка (для строки с вставленными операторами может не быть установлено)
Каждый элемент branch имеет следующий вид:
{ "count": 11, "destination_block_id": 17, "fallthrough": true, "source_block_id": 13, "throw": false }Поля элемента branch имеют следующий смысл:
- count: количество выполнений ветви
- fallthrough: true, если ветвь является ветвью прохода
- throw: true, если ветвь является исключительной ветвью
- isource_block_id: идентификатор базового блока, где происходит ветвление
- destination_block_id: идентификатор базового блока, куда переходит эта ветвь
Каждый элемент call имеет следующий вид:
{ "destination_block_id": 1, "returned": 11, "source_block_id": 13 }Поля элемента call имеют следующий смысл:
- returned: количество раз, когда вызов функции возвращал значение (количество вызовов равно line::count)
- isource_block_id: идентификатор базового блока, где происходит вызов
- destination_block_id: идентификатор базового блока, на который вызов продолжает выполняться после возврата
Каждый элемент condition имеет следующий вид:
{ "count": 4, "covered": 2, "not_covered_false": [], "not_covered_true": [0, 1], }Поля элемента condition имеют следующий смысл:
- count: количество результатов условий в этом выражении
- covered: количество покрытых результатов условий в этом выражении
- not_covered_true: термины по индексу, не наблюдаемые как true в этом выражении
- not_covered_false: термины по индексу, не наблюдаемые как false в этом выражении
-H--human-readable-
Записать счётчики в удобочитаемом формате (например, 24,6 тыс.).
-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 использует полный путь к исходным файлам для создания имени выходного файла. Это может привести к длинным именам файлов, которые могут превышать ограничения файловой системы. Этот параметр создает имена в формате имя_исходного_файла##md5.gcov, где компонент имя_исходного_файла — это конечное имя файла, а компонент md5 рассчитывается по полному искажённому имени, которое было бы использовано в противном случае. Этот параметр является альтернативой –preserve-paths на системах, имеющих ограничение файловой системы.
gcov необходимо запускать с текущей директорией, такой же, как при вызове компилятора. В противном случае он не сможет найти исходные файлы. gcov создаёт файлы с именем искажённое_имя.gcov в текущей директории. Они содержат информацию о покрытии исходного файла, которому соответствуют. Один файл .gcov создаётся для каждого исходного (или заголовочного) файла, содержащего код, который был скомпилирован для создания файлов данных. Часть искажённое_имя имени выходного файла обычно просто имя исходного файла, но может быть более сложной, если заданы параметры ‘-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.
Некоторые строки информации в начале имеют номер_строки ноль. Эти строки преамбулы имеют вид
-:0:tag:value
Порядок и количество этих строк преамбулы будут дополняться по мере развития gcov — не полагайтесь на их неизменность. Используйте метку для поиска конкретной строки преамбулы.
Дополнительная информация о блоках имеет вид
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-14.2.0/gcc/Invoking-Gcov.html