Гид по технологиям

Руководство по Gprof: профилирование C/Fortran на Linux

• 7 min read • Разработка • Обновлено 26 Nov 2025
Gprof: профилирование C/Fortran на Linux
Gprof: профилирование C/Fortran на Linux

Gprof — классический инструмент для профилирования программ на C, Pascal и Fortran77 в Unix-подобных системах. В статье показано, как установить Gprof, скомпилировать программу с опцией -pg, собрать gmon.out и прочитать вывод (flat profile и call graph). Также разбор ограничений инструмента и альтернативы для более сложных задач.

Для кого это руководство

Для разработчиков, которые пишут на C/Fortran и используют Linux как платформу разработки. Подойдёт как быстрый вводный материал и чеклист для первичного анализа «горячих точек» в коде.

Что такое Gprof?

Gprof — это инструмент профилирования, который собирает статистику выполнения: сколько времени и сколько вызовов приходятся на каждую функцию. Он использует генерацию служебного кода при компиляции (опция -pg у gcc), создаёт файл gmon.out и затем анализирует его, выводя две основные секции:

  • Плоский профиль (flat profile): сколько времени заняла каждая функция и сколько раз она была вызвана. Это помогает быстро увидеть «пожирателей циклов».
  • Граф вызовов (call graph): кто кого вызывал, сколько раз, и какова оценка времени, потраченного в дочерних функциях. Это полезно, чтобы понять вклад вложенных вызовов.

Краткое определение: профилирование — измерение времени и частоты вызовов функций, чтобы найти узкие места производительности.

Системные требования и примечания

  • Примеры тестировались на Ubuntu 14.04 LTS с gprof 2.24. На других дистрибутивах поведение может незначительно отличаться.
  • Gprof подходит для одно-процессных и несложных многопоточных программ, но имеет ограничения (ниже).

Важно: чтобы gprof собирал данные, исходники и линковка должны выполняться с опцией -pg.

Установка Gprof

Проверьте, установлен ли gprof командой:

$ gprof

Если вы увидите сообщение вида:

$ a.out: No such file or directory

— это означает, что сам бинарный инструмент доступен в системе. Если gprof не найден, установите пакет binutils:

$ apt-get install binutils

Пример использования: шаг за шагом

Ниже — минимальный пример на C, специально написанный для иллюстрации работы gprof.

//test_gprof.c  
  
#include  
  
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;  
}

Скомпилируйте программу с опцией -pg (эта опция добавляет код, записывающий статистику выполнения):

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

Запустите бинарник:

$ ./test_gprof

После выполнения в текущей директории появится файл gmon.out — это сокровищница данных профилирования.

Сгенерируйте удобочитаемый отчёт:

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

Общий синтаксис: gprof [имяисполняемогофайла] gmon.out > [файл_отчёта]

Разбор вывода: flat profile

Ниже — пример секции flat profile, которую выводит gprof:

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

Пояснения к полям (перевод и интерпретация):

  • % time — процент времени процесса, потраченный непосредственно в этой функции (self).
  • cumulative seconds — накопленное суммарное время до текущей строки.
  • self seconds — время, потраченное непосредственно в теле функции (без учёта дочерних вызовов).
  • calls — количество вызовов функции.
  • ms/call (self) — миллисекунд времени на один вызов самой функции.
  • ms/call (total) — миллисекунд времени на вызов вместе с временем дочерних функций.

Объяснение колонок flat profile

Разбор вывода: call graph

Секция call graph показывает, кто кого вызывал и какова оценка времени в дочерних функциях. Пример из вывода ниже:

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]  
-----------------------------------------------  
                                       
[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]

Ниже — несколько скриншотов, поясняющих элементы call graph в выводе gprof:

Скриншот: части call graph и взаимосвязи функций

Скриншот: детализация времени в дочерних вызовах

Скриншот: пример отображения спонтанных вызовов и индексов

Важно: если вы хотите скрыть пояснения и подсказки в выходном файле, используйте опцию -b у gprof.

Частые ошибки и когда Gprof не подойдёт

  • Многопоточность: gprof плохо работает с приложениями, активно использующими pthreads; сбор данных может быть неполным или некорректным.
  • Встроенные (inlined) функции и оптимизации компилятора: агрессивная оптимизация (O2/O3) и inlining изменяют представление функций в профиле.
  • Системные вызовы и внешние библиотеки: время, потраченное внутри ядра или в библиотеке, не всегда корректно приписывается вашим функциям.
  • Краткие/очень быстрые функции: если функция выполняется быстрее разрешения выборки, она может не попасть в статистику.

Если ваша программа многопроцессная, интенсивно использует I/O или требует трассировки системных вызовов, рассмотрите альтернативы ниже.

Альтернативы Gprof (когда нужна другая модель)

  • perf (Linux perf tools): инструмент на более низком уровне, подходит для системных профилей, трассировки и анализа многопоточных приложений.
  • Valgrind + Callgrind / KCachegrind: детальное профилирование вызовов на основе эмуляции — медленнее, но точнее по количеству инструкций/переходов.
  • gperftools (Google Performance Tools): предоставляет heap/CPU профилирование с минимальным влиянием на производительность.
  • oprofile: системный профайлер, работает с ядром и пользовательским пространством.

Выбор зависит от задачи: gprof быстрый и простой для ознакомительного профилирования; perf/valgrind даёт больше точности и возможностей.

Быстрая методика профилирования (минимальная рабочая процедура)

  1. Соберите сборку с символами отладки (опция -g) и добавьте -pg при компиляции и линковке.
  2. Прогоняйте реалистичные сценарии нагрузки, чтобы gmon.out содержал репрезентативные данные.
  3. Сгенерируйте отчёт gprof и откройте flat profile для поиска «горячих» функций.
  4. Изучите call graph, чтобы понять, откуда приходят самые затратные вызовы.
  5. Примените оптимизацию в коде (изменение алгоритма, уменьшение вызовов и пр.) и повторите измерение.
  6. Сравните profile-data.txt до и после изменений.

Минимальная проверка перед релизом: убедиться, что профилирование прогонов с тестовыми данными даёт стабильные результаты и что оптимизации не изменили семантику.

Рекомендации по использованию опции -pg

  • Добавляйте -pg для всех исходных модулей, которые должны участвовать в профилировании; если собрать частично, отчёт будет неполным.
  • При линковке также используйте -pg, иначе runtime-инфраструктура профилирования не будет подключена.
  • Для сборки релизов не оставляйте -pg: он добавляет накладные расходы.

Критерии приёмки

  • Профилирование выполнялось на репрезентативных данных/наборе тестов.
  • Flat profile показывает явные кандидаты для оптимизации (функции с существенным self time).
  • После оптимизаций общее время выполнения снизилось, а функциональность не изменилась.
  • Регрессий в многопоточности/памяти не появилось.

Чек-листы по ролям

Разработчик:

  • Собрать с -pg и -g.
  • Прогнать сценарии и сохранить gmon.out.
  • Сгенерировать profile-data.txt и отметить кандидатов для оптимизации.

Код-ревьювер / тим-лид:

  • Проверить, что изменение улучшает метрики (латентность/время выполнения).
  • Убедиться, что оптимизация не ухудшает читаемость и тесты проходят.

Факто-бокс

  • Формат отчёта делится на flat profile и call graph.
  • gmon.out — бинарный файл с данными профилирования, генерируется при запуске программы, скомпилированной с -pg.
  • Опция gcc -pg обязательна и при компиляции, и при линковке.
  • Для небольших тестов вывод gprof указывает: “Each sample counts as 0.01 seconds” — это сообщение отражает разрешение выборки в конкретном запуске.

Ментальные модели при профилировании

  • «80/20»: часто 20% кода съедают 80% времени — сначала ищите эти «горячие точки» по flat profile.
  • «Верх вниз»: начните с внешних вызовов (main), затем спускайтесь по call graph, чтобы понять контекст затрат.
  • «Измеряй, меняй, проверяй»: одна оптимизация за раз, с измерением до и после.

Примеры паттернов оптимизации

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

Глоссарий (одна строка на термин)

  • Профилирование — измерение времени и частоты выполнения частей программы.
  • Sampling — метод профилирования, где периодически снимаются снимки состояния стека.
  • Instrumentation — вставка кода для подсчёта вызовов/времени.
  • Flat profile — таблица, показывающая время, потраченное непосредственно в функциях.
  • Call graph — граф вызовов, показывающий взаимосвязи между функциями.

Когда переходить на другие инструменты

  • Нужна профилировка ядра/системных вызовов — используйте perf или oprofile.
  • Нужна высокая точность и анализ инструкций — valgrind/callgrind.
  • Нужно минимальное влияние на производительность при сборе данных в проде — рассмотрите gperftools.

Резюме

Gprof — удобный и простой инструмент для начального профилирования приложений на C/Fortran в Linux. Он даёт быстрый flat profile и call graph, достаточные для нахождения очевидных узких мест. Для продвинутого анализа и многопоточных приложений лучше использовать perf или valgrind.

Если вы уже используете Gprof и хотите поделиться приёмами или примерами, оставьте комментарий — практические сценарии и обмен опытом ценны для сообщества.

Заключение

Мы затронули основы: установка, компиляция с -pg, запуск, генерация profile-data.txt и разбор flat profile и call graph. Это отправная точка — дальше можно изучать опции gprof и переходить к более мощным инструментам при необходимости.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Несколько аккаунтов Skype: Multi Skype Launcher
Программное обеспечение

Несколько аккаунтов Skype: Multi Skype Launcher

Журнал для работы: повысить продуктивность
Productivity

Журнал для работы: повысить продуктивность

Персональные звуки уведомлений на Android
Android.

Персональные звуки уведомлений на Android

Скачивание шоу Hulu для офлайн‑просмотра
Стриминг

Скачивание шоу Hulu для офлайн‑просмотра

Microsoft Start: персонализированная новостная лента
Новости

Microsoft Start: персонализированная новостная лента

Как изменить имя в Epic Games быстро
Гайды

Как изменить имя в Epic Games быстро