TL; Процесс обратного отслеживания перфорирования DR может остановиться на некоторой функции, если в стеке не сохранен указатель фрейма или нет таблиц CFI для метода dwarf. Перекомпилируйте библиотеки с -fno-omit-frame-pointer
или -g
или получите debuginfo. С выпуском двоичных файлов и библиотек Perf часто останавливает обратную трассировку на ранней стадии, не имея возможности достичь main()
или _start
или clone()/start_thread()
верхних функций. бинарный инструментарий): он программирует программный таймер или источник событий или блок мониторинга производительности оборудования (PMU) для генерации прерывания periodi c. В вашем примере -c 10000 -e mem_load_uops_retired.l3_miss:uppp
используется для выбора аппаратного PMU в x86_64 в каком-то режиме PEBS (https://easyperf.net/blog/2018/06/08/Advanced-profiling-topics-PEBS-and-LBR) для генерации прерывания после 10000 mem_load_uops_retired (с маской l3_miss). Сгенерированное прерывание обрабатывается ядром Linux (подсистема perf_events , ядро / события и arch / x86 / events ). В этом обработчике PMU сбрасывается (перепрограммируется) для генерации следующего прерывания после 10000 дополнительных событий и генерации выборки. Дамп данных сэмплов сохраняется в файле perf.data командой perf report
, но при каждом запуске инструмента можно сохранять тысячи сэмплов; Сэмплы могут быть прочитаны perf script
или perf script -D
.
обработчиком прерываний perf_events, что-то около __perf_event_overflow
ядра / событий / ядра. c, имеет полный доступ к регистрирует текущую функцию и имеет некоторое время, чтобы выполнить дополнительный поиск данных для записи текущего времени, pid, et c. Частью такого процесса является https://en.wikipedia.org/wiki/Call_stack сбор данных. Но с x86_64 и -fomit-frame-pointer (часто включаемым для многих системных библиотек Debian / Ubuntu / others) нет места по умолчанию в регистрах или в стеке функций для хранения указателей фреймов:
https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Optimize-Options.html#index -fomit_002dframe_002dpointer-692
-fomit-frame-pointer
Не храните указатель кадра в регистре для функций, которые в нем не нуждаются. Это позволяет избежать инструкций по сохранению, настройке и восстановлению указателей кадров; это также делает дополнительный регистр доступным во многих функциях. Это также делает невозможной отладку на некоторых машинах.
Начиная с G CC версии 4.6, настройка по умолчанию (без оптимизации по размеру) для 32-битных Linux x86 и 32-битных целей Darwin x86 имеет был изменен на -fomit-frame-pointer. Значение по умолчанию можно вернуть к -fno-omit-frame-pointer, сконфигурировав G CC с опцией настройки --enable-frame-pointer.
С указателями кадров, сохраненными в трассировке стека функций / разматывать легко. Но для некоторых функций современные g cc (и другие компиляторы) могут не генерировать указатель кадра. Поэтому код обратной трассировки, такой как в обработчике perf_events, либо остановит обратную трассировку при такой функции, либо нуждается в другом методе восстановления указателя кадра. Опция -g method
(--call-graph
) из perf record
выбирает метод, который будет использоваться. Это задокументировано в man perf-record
http://man7.org/linux/man-pages/man1/perf-record.1.html:
--call-graph
Настройка и включение записи графа вызовов (цепочка стека / обратная трассировка), подразумевает -g. По умолчанию установлено значение «fp».
Позволяет указать «fp» (указатель кадра) или «dwarf» (CFI DWARF - Информация о кадре вызова) или «lbr» (аппаратная запись последней ветви) в качестве метода сбора информация, используемая для отображения графиков вызовов.
В некоторых системах, где двоичные файлы создаются с помощью g cc
--fomit-frame-pointer, использование метода "fp" приведет к созданию поддельных графиков вызовов, с использованием «dwarf», если доступно (инструменты perf, связанные с библиотекой libunwind или libdw) должны использоваться вместо этого. Использование метода "lbr" не требует никаких параметров компилятора. Он будет генерировать графы вызовов из аппаратных регистров LBR. Основным ограничением является то, что он доступен только на новых платформах Intel, таких как Haswell. Это может получить только пользовательская цепочка вызовов. Он не работает с выборкой из стека ветвей одновременно.
Когда используется запись "dwarf", perf также записывает (пользовательский) дамп стека при выборке. Размер дампа стека по умолчанию составляет 8192 (байт). пользователь можно изменить размер, передав размер после запятой, например
"--call-graph dwarf, 4096".
Таким образом, метод dwarf повторно использует таблицы CFI для поиска размеров кадра стека и поиска стека вызывающей стороны Рамка. Я не уверен, что таблицы CFI удалены из библиотек релизов по умолчанию или нет; но у debuginfo, вероятно, они будут. LBR не поможет, потому что это довольно короткий аппаратный буфер. Обработка разбиения карликов (обработчик ядра сохраняет часть стека, а инструментальное пространство пользователя perf проанализирует его с помощью libdw + libunwind) может потерять некоторые части стека вызовов, поэтому попробуйте также увеличить дамп стека карликов с помощью --call-graph dwarf,10240
или --call-graph dwarf,81920
et c.
Обратное отслеживание реализовано в зависимой от арки части perf_events: arch / x86 / events / core. c: perf_callchain_user()
; вызывается из kernel / events / callchain. c: get_perf_callchain()
<- perf_callchain <- <a href="https://elixir.bootlin.com/linux/v4.19.107/source/kernel/events/core.c#L6445" rel="nofollow noreferrer"> perf_prepare_sample <- <a href="https://elixir.bootlin.com/linux/v4.19.107/source/kernel/events/core.c#L6569" rel="nofollow noreferrer"> __ perf_event_output <- <a href="https://elixir.bootlin.com/linux/v4.19.107/source/kernel/events/core.c#L10111" rel="nofollow noreferrer">*(event->overflow_handler)
<- <code>READ_ONCE(event->overflow_handler)(event, data, regs); из __perf_event_overflow
.
Грегг предупредил о неполных стеках вызовов perf: http://www.brendangregg.com/blog/2014-06-22/perf-cpu-sample.html
Неполные стеки обычно означают, что использовался -fomit-frame-pointer - оптимизация компилятора, которая мало что меняет в реальном мире, но ломает профилировщики стека. Всегда компилируйте с -fno-omit-frame-pointer. Более поздняя версия perf имеет опцию -g dwarf, чтобы использовать альтернативный метод libunwind / dwarf для извлечения стеков.
Я также писал о обратных трассировках в perf с некоторыми дополнительными ссылками: Как работает linux Утилита perf понимает следы стека?