Spec-Zone.ru › GCC 10

Далее: Использование gcov с оптимизацией GCC, Предыдущее: Введение в gcov, Вверх: gcov—Программа тестирования покрытия кода [Оглавление][Индекс]

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 (в стандартном выводе) и завершает работу, не выполняя дальнейшей обработки.

-i
--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, если ветвление является исключительной ветвью
-j
--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
$ 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; если файл не соответствует исполняемому файлу (различается количество базовых блоков), он игнорирует содержимое файла. Затем он добавляет новые счёты выполнения и, наконец, записывает данные в файл.

Далее: Использование gcov с оптимизацией GCC, Предыдущее: Введение в gcov, Наверх: gcov — программа для тестирования покрытия кода [Содержание][Индекс]

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-10.5.0/gcc/Invoking-Gcov.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API