Как утилита linux perf понимает трассировку стека?

Linux-утилита для Linux отлично известна Брендану Греггу для создания плагинов для c/С++, jvm-кода, кода nodejs и т.д.

Ядро Linux отлично понимает трассировку стека? Где я могу узнать больше о том, как инструмент способен интроспективно отслеживать стеки процессов, даже если процессы написаны на совершенно разных языках?

Ответ 1

Существует краткое введение о трассировке стека в perf от Gregg: http://www.brendangregg.com/perf.html

4.4 Трассировка стека

Всегда компилируйте с помощью указателей на рамки. Опускание указателей на кадры - это злая оптимизация компилятора, которая прерывает отладчики, и, к сожалению, часто используется по умолчанию. Без них вы можете видеть неполные стеки с perf_events... Есть два способа исправить это: либо использовать данные карликов, чтобы разматывать стек, либо возвращать указатели на фреймы.

Гном

Начиная с ядра 3.9, perf_events поддерживает обходное решение для отсутствующих указателей на фреймы уровня пользователя: libunwind, который использует карлик. Это можно активировать с помощью "-g dwarf".... оптимизация компилятора (-O2), которая в этом случае опустила указатель на фрейм.... перекомпиляция.. с помощью -fno-omit-frame-pointer:

Языки, не относящиеся к C, могут иметь другой формат кадра или могут также опускать указатели на рамки:

4,3. Символы JIT (Java, Node.js)

Программы, в которых виртуальные машины (виртуальные машины), такие как Java JVM и node v8, выполняют собственный виртуальный процессор, который имеет свой собственный способ выполнения функций и управления стеками. Если вы профилируете их с помощью perf_events, вы увидите символы для механизма VM. Perf_events имеет поддержку JIT для решения этой проблемы, которая требует, чтобы виртуальная машина поддерживала файл /tmp/perf-PID.map для перевода символов.

Обратите внимание, что Java может не отображать полные стеки для начала, из-за того, что hotspot на x86 удаляет указатель кадра (точно так же, как gcc). В более новых версиях (JDK 8u60 +) вы можете использовать параметр -XX:+PreserveFramePointer, чтобы исправить это поведение,...

Сообщение в блоге Gregg о трассировке Java и стека: http://techblog.netflix.com/2015/07/java-in-flames.html ( "Fixing Frame Pointers" - исправлено в некоторых версиях JDK8 и в JDK9 путем добавления опции при запуске программы)

Теперь ваши вопросы:

Как утилита linux perf понимает трассировки стека?

perf утилита в основном (в ранних версиях) просто анализирует данные, возвращаемые из подсистемы Linux linux < <26 > "(или иногда" events "), доступ к которым осуществляется с помощью syscall perf_event_open. Для трассировки стека вызовов есть опции PERF_SAMPLE_CALLCHAIN/PERF_SAMPLE_STACK_USER:

sample_type             PERF_SAMPLE_CALLCHAIN                    Записывает цепочку звонков (backtrace стека).

          PERF_SAMPLE_STACK_USER (since Linux 3.7)
                 Records the user level stack, allowing stack unwinding.

Ядро Linux отлично понимает трассировку стека?

Он может понять (если он реализован) и не может, в зависимости от вашей архитектуры процессора. Функция вызова (считывания/чтения вызова из живого процесса) callchain определена в независимой от архитектуры части ядра как __weak с пустым телом:

http://lxr.free-electrons.com/source/kernel/events/callchain.c?v=4.4#L26

 27 __weak void perf_callchain_kernel(struct perf_callchain_entry *entry,
 28                                   struct pt_regs *regs)
 29 {
 30 }
 31 
 32 __weak void perf_callchain_user(struct perf_callchain_entry *entry,
 33                                 struct pt_regs *regs)
 34 {
 35 }

В 4.4 ядре пользовательского пространства callchain sampler переопределяется в зависимой от архитектуры части ядра для x86/x86_64, ARC, SPARC, ARM/ARM64, Xtensa, Tilera TILE, PowerPC, Imagination Meta:

http://lxr.free-electrons.com/ident?v=4.4;i=perf_callchain_user

arch/x86/kernel/cpu/perf_event.c, line 2279
arch/arc/kernel/perf_event.c, line 72
arch/sparc/kernel/perf_event.c, line 1829
arch/arm/kernel/perf_callchain.c, line 62
arch/xtensa/kernel/perf_event.c, line 339
arch/tile/kernel/perf_event.c, line 995
arch/arm64/kernel/perf_callchain.c, line 109
arch/powerpc/perf/callchain.c, line 490
arch/metag/kernel/perf_callchain.c, line 59

Чтение цепочек вызовов из пользовательского стека может быть не тривиальным для некоторых архитектур и/или для некоторых режимов.

Какую архитектуру процессора вы используете? Какие языки и виртуальные машины используются?

Где я могу узнать больше о том, как инструмент способен интроспективно отслеживать стеки процессов, даже если процессы написаны на совершенно разных языках?

Вы можете попробовать gdb и/или отладчики для языка или backtrace function libc или поддержку только для чтения в libunwind (есть локальный пример backtrace в libunwind, show_backtrace()).

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

Если они могут получить трассировку вызова, но perf не может (даже после перекомпиляции с помощью -fno-omit-frame-pointer для C/С++), может быть возможно добавить поддержку такой комбинации архитектуры + формат кадра в perf_events и perf.

Есть несколько блогов с некоторой информацией об общих проблемах и решениях backtracing:

Поддержка карлика для perf_events/perf: