Поиск по сайту:

Как установить и использовать инструмент профилирования Gprof в Linux


На этой странице

  1. Что такое Gprof?
  2. Загрузите и установите Gprof
  3. Использование Gprof

Нет никаких сомнений в том, что тестирование является неотъемлемым и одним из наиболее важных аспектов процесса разработки программного обеспечения. И под тестированием мы подразумеваем не просто тестирование кода на наличие ошибок — конечно, обнаружение ошибок важно, поскольку никто не хотел бы, чтобы их программное обеспечение содержало ошибки — производительность кода также имеет большое значение в наши дни.

Если разбить на последний бит, тестирование производительности эффективно проверяет, сколько времени потребляет конкретный фрагмент кода, скажем, функция. Как это обычно бывает, функция или группа функций может соответствовать одной из многих функций программного обеспечения. Таким образом, если с помощью тестирования производительности мы можем повысить производительность этих функций в коде, общая производительность программного обеспечения становится лучше.

Если вы программист, который пишет код на языках программирования C, Pascal или Fortran77 и использует Linux в качестве платформы для разработки, вам будет приятно узнать, что существует мощный инструмент, с помощью которого вы можете проверить производительность своего кода - инструмент речь идет о Gprof. В этом руководстве мы обсудим детали того, как вы можете загрузить, установить и использовать этот инструмент.

Прежде чем мы двинемся дальше, обратите внимание, что все примеры и инструкции, упомянутые в этом руководстве, были протестированы на Ubuntu 14.04LTS, а используемая версия Gprof — 2.24.

Что такое Гпроф?

Итак, что же такое Gprof? Согласно официальной документации инструмента, он предоставляет пользователям профиль выполнения их программ на C, Pascal или Fortran77. По сути, Gprof вычисляет время, затрачиваемое на выполнение каждой процедуры или функции. \Далее эти времена распространяются по краям графа вызовов. Обнаружены циклы, и выполняются вызовы в цикл, чтобы разделить время цикла\.

Если на данный момент все это звучит немного запутанно (особенно часть в кавычках), не беспокойтесь, а также проясните ситуацию на примере. Итак, читайте дальше.

Скачайте и установите Gprof

Сначала проверьте, установлен ли этот инструмент в вашей системе. Для этого просто запустите следующую команду в терминале.

$ gprof

Если вы получаете сообщение об ошибке, например:

$ a.out: No such file or directory

то это будет означать, что инструмент уже установлен. В противном случае вы можете установить его с помощью следующей команды:

$ apt-get install binutils

Использование Gprof

Излишне говорить, что лучший способ понять такой инструмент, как Gprof, — это рассмотреть практический пример. Итак, начнем с программы на языке C, которая хорошо профилируется через Gprof. Вот программа:

//test_gprof.c

#include<stdio.h>

void func4(void)
{
    printf("\n Inside func4() \n");
    for(int count=0;count<=0XFFFF;count++);
}

void func3(void)
{
    printf("\n Inside func3() \n");
    for(int count=0;count<=0XFFFFFFF;count++);
}

void func2(void)
{
    printf("\n Inside func2() \n");

    for(int count=0;count<=0XFFF;count++);

    func3();
}

void func1(void)
{
    printf("\n Inside func1() \n");
    for(int count=0;count<=0XFFFFFF;count++);

    func2();
}

int main(void)
{
    printf("\n main() starts...\n");
    for(int count=0;count<=0XFFFFF;count++);

    func1();
    func4();
    printf("\n main() ends...\n");

    return 0;
}

Обратите внимание, что приведенный выше код (test_gprof.c) специально написан для объяснения Gprof, а не взят из какого-либо реального проекта.

Теперь, двигаясь дальше, следующим шагом будет компиляция этого кода с помощью gcc. Обратите внимание, что в идеале я бы скомпилировал приведенный выше код с помощью следующей команды:

$ gcc -Wall -std=c99 test_gprof.c -o test_gprof

Но поскольку мы профилируем код с помощью Gprof, мне придется использовать параметр командной строки -pg, предоставляемый компилятором gcc. Итак, команда становится:

$ gcc -Wall -std=c99 -pg test_gprof.c -o test_gprof

Если вы посмотрите на справочную страницу gccs, вот что там говорится об опции -pg:

\Создайте дополнительный код для записи информации профиля, подходящей для аналитической программы gprof. Вы должны использовать этот параметр при компиляции исходных файлов, о которых вам нужны данные, а также использовать его при связывании.\

Теперь, возвращаясь к приведенной выше команде, после успешного выполнения она создаст на выходе двоичный файл с именем test_gprof. Следующим шагом является запуск этого исполняемого файла. Вот как я запустил бинарник в моем случае:

$ ./test_gprof

После выполнения команды вы увидите, что в текущем рабочем каталоге будет создан файл с именем gmon.out.

$ ls gmon*
gmon.out


Именно этот файл содержит всю информацию, которая требуется инструменту Gprof для создания удобочитаемых данных профилирования. Итак, теперь используйте инструмент Gprof следующим образом:

$ gprof test_gprof gmon.out > profile-data.txt

По сути, общий синтаксис этой команды:

$ gprof [executable-name] gmon.out > [name-of-file-that-will-contain-profiling-data]

Теперь, прежде чем мы увидим информацию, содержащуюся в файле profile-data.txt, стоит упомянуть, что удобочитаемый вывод, который создает Gprof, разделяется на две части: плоский профиль и график вызовов. Вот что говорит справочная страница Gprof об информации в этих двух разделах:

\Плоский профиль показывает, сколько времени ваша программа провела в каждой функции и сколько раз эта функция была вызвана. Если вы просто хотите знать, какие функции сжигают больше всего циклов, это кратко указано здесь\.

\Диаграмма вызовов показывает для каждой функции, какие функции вызывали ее, какие другие функции она вызывала и сколько раз. Существует также оценка того, сколько времени было потрачено на подпрограммы каждой функции. Это может предложите места, где вы могли бы попытаться исключить вызовы функций, отнимающие много времени.\

Вооружившись этой информацией, вы сможете лучше понять данные, представленные в выходном файле профилирования (в моем случае profile-data.txt). Вот плоский профиль в моем случае:

Flat profile:

Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
96.43 0.81 0.81 1 810.00 810.00 func3
3.57 0.84 0.03 1 30.00 840.00 func1
0.00 0.84 0.00 1 0.00 810.00 func2
0.00 0.84 0.00 1 0.00 0.00 func4

И вот что означает каждое поле:

Двигаясь дальше, вот график вызовов в моем случае:

Call graph (explanation follows)


granularity: each sample hit covers 4 byte(s) for 1.19% of 0.84 seconds

index % time self children called name
0.03 0.81 1/1 main [2]
[1] 100.0 0.03 0.81 1 func1 [1]
0.00 0.81 1/1 func2 [3]
-----------------------------------------------
<spontaneous>
[2] 100.0 0.00 0.84 main [2]
0.03 0.81 1/1 func1 [1]
0.00 0.00 1/1 func4 [5]
-----------------------------------------------
0.00 0.81 1/1 func1 [1]
[3] 96.4 0.00 0.81 1 func2 [3]
0.81 0.00 1/1 func3 [4]
-----------------------------------------------
0.81 0.00 1/1 func2 [3]
[4] 96.4 0.81 0.00 1 func3 [4]
-----------------------------------------------
0.00 0.00 1/1 main [2]
[5] 0.0 0.00 0.00 1 func4 [5]

На следующих снимках экрана поясняется информация, содержащаяся на графике вызовов:

Если вас интересует источник приведенных выше снимков экрана, позвольте мне сказать вам, что вся эта информация находится в выходном файле, который содержит информацию о профилировании, включая плоский профиль и график вызовов. Если вы хотите, чтобы эта информация была исключена из вывода, вы можете использовать параметр -b, предоставленный Gprof.

Заключение

Излишне говорить, что здесь мы только коснулись поверхности, так как Gprof предлагает множество функций (просто взгляните на его справочную страницу). Однако того, что мы здесь рассмотрели, должно быть достаточно, чтобы вы начали. Если вы уже используете Gprof и хотите поделиться чем-то, связанным с этим инструментом, просто оставьте комментарий ниже.