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": current_working_directory, "data_file": data_file, "format_version": format_version, "gcc_version": gcc_version "files": [file] }Поля корневого элемента имеют следующее значение:
- current_working_directory: рабочая директория, где был скомпилирован компилируемый модуль
- data_file: имя файла данных (GCDA)
- format_version: семантическая версия формата
- gcc_version: версия компилятора GCC
Каждый элемент file имеет следующий вид:
{ "file": file_name, "functions": [function], "lines": [line] }Поля элемента file имеют следующее значение:
- file_name: имя исходного файла
Каждый элемент function имеет следующий вид:
{ "blocks": blocks, "blocks_executed": blocks_executed, "demangled_name": "demangled_name, "end_column": end_column, "end_line": end_line, "execution_count": execution_count, "name": name, "start_column": start_column "start_line": start_line }Поля элемента 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": count, "line_number": line_number, "unexecuted_block": unexecuted_block "function_name": function_name, }Ветвления присутствуют только с параметром -b. Поля элемента line имеют следующее значение:
- count: количество выполнений строки
- line_number: номер строки
- unexecuted_block: флаг, указывающий, содержит ли строка невыполненный блок (не все операторы в строке выполняются)
- function_name: имя функции, к которой принадлежит эта строка (для строки с встраиваемыми операторами может не быть задано)
Каждый элемент branch имеет следующий вид:
{ "count": count, "fallthrough": fallthrough, "throw": throw }Поля элемента 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
Порядок и количество этих строк преамбулы будут изменены по мере развития gcov, — не полагайтесь на их неизменность. Используйте 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-11.4.0/gcc/Invoking-Gcov.html