Linux の perf ユーティリティは、Brendan Gregg が c/c++、jvm コード、nodejs コードなどのフレームグラフを生成するために使用したことで有名です。
Linux カーネルはスタック トレースをネイティブに理解しますか? プロセスがまったく異なる言語で記述されている場合でも、ツールがプロセスのスタック トレースをどのようにイントロスペクトできるかについて、どこで詳しく読むことができますか?
Linux の perf ユーティリティは、Brendan Gregg が c/c++、jvm コード、nodejs コードなどのフレームグラフを生成するために使用したことで有名です。
Linux カーネルはスタック トレースをネイティブに理解しますか? プロセスがまったく異なる言語で記述されている場合でも、ツールがプロセスのスタック トレースをどのようにイントロスペクトできるかについて、どこで詳しく読むことができますか?
perf
Gregg による
スタック トレースに関する短い紹介があります: http://www.brendangregg.com/perf.html
4.4 スタック トレース
常にフレーム ポインターを使用してコンパイルします。フレーム ポインターを省略することは、デバッガーを破壊する悪意のあるコンパイラーの最適化であり、悲しいことに、多くの場合デフォルトです。それらがないと、perf_events からの不完全なスタックが表示される場合があります。これを修正するには 2 つの方法があります。ドワーフ データを使用してスタックをアンワインドするか、フレーム ポインターを返すかのいずれかです。
ドワーフ
3.9 カーネル以降、perf_events は、ユーザー レベル スタックでフレーム ポインターが欠落している場合の回避策をサポートしています。つまり、dwarf を使用する libunwind です。これは、「-g dwarf」を使用して有効にできます。... コンパイラの最適化 (
-O2
)。この場合、フレーム ポインタが省略されています。... 再コンパイル中 ..-fno-omit-frame-pointer
:
C スタイル以外の言語では、フレーム形式が異なる場合や、フレーム ポインターが省略されている場合もあります。
4.3. JIT シンボル (Java、Node.js)
Java の JVM やノードの v8 などの仮想マシン (VM) を持つプログラムは、関数を実行し、スタックを管理する独自の方法を持つ独自の仮想プロセッサを実行します。perf_events を使用してこれらをプロファイリングすると、VM エンジンのシンボルが表示されます。perf_events には、これを解決するための JIT サポートがあり、VM
/tmp/perf-PID.map
はシンボル変換用のファイルを維持する必要があります。x86 のホットスポットがフレーム ポインターを省略しているため (gcc と同様)、Java は最初から完全なスタックを表示しない場合があることに注意してください。新しいバージョン (JDK 8u60+) では、
-XX:+PreserveFramePointer
オプションを使用してこの動作を修正できます...
Java とスタック トレースに関する Gregg のブログ投稿: http://techblog.netflix.com/2015/07/java-in-flames.html (「Fixing Frame Pointers」 - 一部の JDK8 バージョンと JDK9 では、オプションを追加することで修正されました。プログラム開始)
さて、あなたの質問:
Linux の perf ユーティリティはスタック トレースをどのように理解しますか?
perf
ユーティリティは基本的に (初期のバージョンでは) syscall でアクセスされるLinux カーネルのサブシステム " perf_events
" (または " ") から返されたデータを解析するだけです。コール スタック トレースには、オプション/があります。events
perf_event_open
PERF_SAMPLE_CALLCHAIN
PERF_SAMPLE_STACK_USER
sample_type PERF_SAMPLE_CALLCHAIN コールチェーン (スタック バックトレース) を記録します。
PERF_SAMPLE_STACK_USER (since Linux 3.7)
Records the user level stack, allowing stack unwinding.
Linux カーネルはスタック トレースをネイティブに理解しますか?
CPU アーキテクチャによっては、(実装されている場合) 理解できる場合と理解できない場合があります。サンプリング機能 (ライブ プロセスからのコール スタックの取得/読み取り) コールチェーンは、カーネルのアーキテクチャに依存しない部分で__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 カーネルのユーザー空間コールチェーン サンプラーは、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
ユーザー スタックからの呼び出しチェーンの読み取りは、一部のアーキテクチャや一部のモードでは簡単ではない場合があります。
どのCPUアーキテクチャを使用していますか? どの言語と VM が使用されていますか?
プロセスがまったく異なる言語で記述されている場合でも、ツールがプロセスのスタック トレースをどのようにイントロスペクトできるかについて、どこで詳しく読むことができますか?
libc の言語または機能、または libunwind での読み取り専用巻き戻しのサポートについてはgdb
、および/またはデバッガーを試すことができます ( libunwindにローカル バックトレースの例があります)。backtrace
show_backtrace()
フレーム解析のサポートが改善されているか、言語の仮想マシンまたはアンワインド情報との統合が改善されている可能性があります。gdb (backtrace
コマンドを使用) または他のデバッガーが実行中のプログラムからスタック トレースを取得できない場合、スタック トレースを取得する方法がまったくない可能性があります。
コール トレースを取得できるが、perf
(C/C++ 用に再コンパイルした後でも) 取得できない場合は、そのようなアーキテクチャ + フレーム形式の組み合わせのサポートをおよび-fno-omit-frame-pointer
に追加できる可能性があります。perf_events
perf
一般的なバックトレースの問題と解決策に関する情報が記載されたブログがいくつかあります。
__builtin_return_address(N)
と glibcbacktrace()
と libunwind のローカル バックトレースperf_events
/のドワーフ サポートperf
: