Spec-Zone.ru › GCC 9

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,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 использует полное имя пути исходных файлов для создания имени выходного файла. Это может привести к длинным именам файлов, которые могут превысить ограничения файловой системы. Этот параметр создаёт имена в формате 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.

Некоторые строки информации в начале имеют номер_строки ноль. Эти строки преамбулы имеют вид

-: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
$ 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 и оптимизация, Предыдущий: Введение в Gcov, Вверх: Gcov [Оглавление][Индекс]

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

Spec-Zone.ru

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