perf - это статистический (выборочный) профилировщик (в его режиме по умолчанию perf record
), и это означает, что он не имеет точных отметок времени при входе и выходе из функции (для точных данных требуется трассировка). Perf просит ядро ОС генерировать прерывания тысячи раз в секунду (4 кГц для аппаратного PMU, если поддерживается -e cycles
, меньше для программного события -e cpu-clock
). Каждое прерывание выполнения программы записывается как образец, который содержит EIP (текущий указатель инструкции), pid (идентификатор процесса / потока), временную метку текущего времени. Когда программа работает в течение нескольких секунд, будут тысячи выборок, и perf report
может генерировать из них гистограммы: какие части программного кода (какие функции) выполнялись чаще, чем другие. Вы получите общий c обзор того, что некоторые функции занимали около 30% времени выполнения программы, а другие - 5%.
отчет perf не вычисляет общее время выполнения программы (он может оценить его, сравнив временные метки первый и последний образцы, но это не точно, если бы были периоды отсутствия процессора). Но он оценивает общее количество событий (оно печатается в первой строке интерактивного интерфейса пользователя и указывается в текстовом выводе):
$ perf report |grep approx
# Samples: 1K of event 'cycles'
# Event count (approx.): 844373507
Существует опция perf report -n
, которая добавляет столбец «количество образцов» рядом с столбец процентов.
Samples: 1K of event 'cycles', Event count (approx.): 861416907
Overhead Samples Command Shared Object Symbol
42.36% 576 bc bc [.] _bc_rec_mul
37.49% 510 bc bc [.] _bc_shift_addsub.isra.3
14.90% 202 bc bc [.] _bc_do_sub
0.89% 12 bc bc [.] bc_free_num
Но выборки берутся с разными интервалами и они менее точны, чем вычисленные накладные расходы (каждая выборка может иметь разный вес). Я рекомендую вам запустить perf stat ./application
, чтобы получить реальное общее время работы и общее количество оборудования для вашего приложения. Лучше, когда ваше приложение имеет стабильное время работы (сделайте perf stat -r 5 ./application
, чтобы вариация оценивалась инструментом как "+ - 0,28%" в последнем столбце)
Для включения дочерних функций трассировки стека должны отбираться при каждом прерывании . Они не выбираются в режиме по умолчанию perf record
. Эта выборка включается с параметрами -g
или --call-graph dwarf
: perf record -g ./application
или perf record --call-graph dwarf ./application
. Его непросто правильно использовать для предустановленных библиотек или приложений в Linux (поскольку большинство дистрибутивов удаляют отладочную информацию из пакетов), но его можно использовать для ваших собственных приложений, скомпилированных с отладочной информацией. Значение по умолчанию -g
, которое совпадает с --call-graph fp
, требует, чтобы весь код был скомпилирован с параметром -fno-omit-frame-pointer
g cc, а нестандартный --call-graph dwarf
более надежен. С правильно подготовленной программой и библиотеками, однопоточным приложением и достаточно длинными образцами размера стека (по умолчанию 8 КБ, измените на --call-graph dwarf,65536
), perf report
должно показать около 99% для _start
и main
функций (включая дочерние ).
b c калькулятор скомпилирован с -fno-omit-frame-pointer
:
bc-no-omit-frame$ echo '3^123456%3' | perf record -g bc/bc
bc-no-omit-frame$ perf report
Samples: 1K of event 'cycles:uppp', Event count (approx.): 811063902
Children Self Command Shared Object Symbol
+ 98.33% 0.00% bc [unknown] [.] 0x771e258d4c544155
+ 98.33% 0.00% bc libc-2.27.so [.] __libc_start_main
+ 98.33% 0.00% bc bc [.] main
b c калькулятор с графиком гномьих вызовов:
$ echo '3^123456%3' | perf record --call-graph dwarf bc/bc
$ perf report
Samples: 1K of event 'cycles:uppp', Event count (approx.): 898828479
Children Self Command Shared Object Symbol
+ 98.42% 0.00% bc bc [.] _start
+ 98.42% 0.00% bc libc-2.27.so [.] __libc_start_main
+ 98.42% 0.00% bc bc [.] main
b c без отладочной информации имеет некорректную обработку графа вызовов с помощью perf в режиме -g
(fp) (нет 99% для основного):
$ cp bc/bc bc.strip
$ strip -d bc.strip
$ echo '3^123456%3' | perf record --call-graph fp ./bc.strip
Samples: 1K of event 'cycles:uppp', Event count (approx.): 841993392
Children Self Command Shared Object Symbol
+ 43.94% 43.94% bc.strip bc.strip [.] _bc_rec_mul
+ 39.73% 39.73% bc.strip bc.strip [.] _bc_shift_addsub.isra.3
+ 11.27% 11.27% bc.strip bc.strip [.] _bc_do_sub
+ 0.92% 0.92% bc.strip libc-2.27.so [.] malloc
Иногда perf report --no-children
может быть полезно для отключения сортировки по self + children накладные расходы (будут отсортированы по «собственным» накладным расходам), например, когда граф вызовов не был полностью захвачен.