49

今日、Linux のperfユーティリティを試してみましたが、結果の解釈に問題があります。私は valgrind の callgrind に慣れていますが、これはもちろん、サンプリング ベースの perf メソッドとはまったく異なるアプローチです。

私がしたこと:

perf record -g -p $(pidof someapp)
perf report -g -n

今、私はこのようなものを見ます:

+ 16.92% kdevelop libsqlite3.so.0.8.6 [.] 0x3fe57 ↑
+ 10.61% kdevelop libQtGui.so.4.7.3 [.] 0x81e344 ▮
+ 7.09% kdevelop libc-2.14.so [.] 0x85804 ▒
+ 4.96% kdevelop libQtGui.so.4.7.3 [.] 0x265b69 ▒
+ 3.50% kdevelop libQtCore.so.4.7.3 [.] 0x18608d ▒
+ 2.68% kdevelop libc-2.14.so [.] memcpy ▒
+ 1.15% kdevelop [kernel.kallsyms] [k] copy_user_generic_string ▒
+ 0.90% kdevelop libQtGui.so.4.7.3 [.] QTransform::translate(double, double) ▒
+ 0.88% kdevelop libc-2.14.so [.] __libc_malloc ▒
+ 0.85% kdevelop libc-2.14.so [.] memcpy
...

これらの関数は遅いかもしれませんが、どこから呼び出されているかを知るにはどうすればよいでしょうか? これらのホットスポットはすべて外部ライブラリにあるため、コードを最適化する方法がわかりません。

基本的に、累積コストで注釈が付けられたある種のコールグラフを探しています。ここで、関数は、呼び出したライブラリ関数よりも包括的なサンプリング コストが高くなります。

これはperfで可能ですか?もしそうなら - どのように?

注:「E」はコールグラフをアンラップし、より多くの情報を提供することがわかりました。しかし、コールグラフは多くの場合、十分に深くないか、どこでどれだけの情報が費やされたかに関する情報を提供せずにランダムに終了します。例:

- 10.26% kate libkatepartinterfaces.so.4.6.0 [.] Kate::TextLoader::readLine(int&...
     Kate::TextLoader::readLine(int&, int&)                                            
     Kate::TextBuffer::load(QString const&, bool&, bool&)                              
     KateBuffer::openFile(QString const&)                                              
     KateDocument::openFile()                                                          
     0x7fe37a81121c

64ビットで実行していることが問題になる可能性はありますか? http://lists.fedoraproject.org/pipermail/devel/2010-November/144952.htmlも参照してください(私は fedora を使用していませんが、すべての 64 ビット システムに適用されるようです)。

4

5 に答える 5

47

Linux 3.7 では、perf は DWARF 情報を使用してコールグラフを生成できるようになりました。

perf record --call-graph dwarf -- yourapp
perf report -g graph --no-children

きちんとしていますが、curses GUI は VTune や KCacheGrind などに比べてひどいものです...代わりに、FlameGraphs を試すことをお勧めします。

注: レポート ステップで-g graphは、結果出力が単純になり、「親に対する相対」数値ではなく、「合計に対する相対」パーセンテージがわかりやすくなります。--no-children包括的なコストではなく、自己コストのみが表示されます。これも非常に貴重な機能です。

新しいパフォーマンスと Intel CPU を使用している場合は、LBR アンワインダーも試してみてください。パフォーマンスが大幅に向上し、はるかに小さな結果ファイルが生成されます。

perf record --call-graph lbr -- yourapp

ここでの欠点は、デフォルトの DWARF アンワインダー構成と比較して、呼び出しスタックの深さがより制限されていることです。

于 2012-12-17T23:20:17.347 に答える
22

これらの関数は遅いかもしれませんが、どこから呼び出されているかを知るにはどうすればよいでしょうか? これらのホットスポットはすべて外部ライブラリにあるため、コードを最適化する方法がわかりません。

あなたのアプリケーションsomeappが gcc オプション-fno-omit-frame-pointer(およびおそらくその依存ライブラリ) を使用してビルドされていることは確かですか? このようなもの:

g++ -m64 -fno-omit-frame-pointer -g main.cpp
于 2012-11-22T08:50:01.290 に答える
15

を使用して、非常に詳細なソース レベルのレポートを取得できます。perf annotate を使用したソース レベルの分析をperf annotate参照してください。次のようになります (ウェブサイトから恥知らずに盗みました)。

------------------------------------------------
 Percent |   Source code & Disassembly of noploop
------------------------------------------------
         :
         :
         :
         :   Disassembly of section .text:
         :
         :   08048484 <main>:
         :   #include <string.h>
         :   #include <unistd.h>
         :   #include <sys/time.h>
         :
         :   int main(int argc, char **argv)
         :   {
    0.00 :    8048484:       55                      push   %ebp
    0.00 :    8048485:       89 e5                   mov    %esp,%ebp
[...]
    0.00 :    8048530:       eb 0b                   jmp    804853d <main+0xb9>
         :                           count++;
   14.22 :    8048532:       8b 44 24 2c             mov    0x2c(%esp),%eax
    0.00 :    8048536:       83 c0 01                add    $0x1,%eax
   14.78 :    8048539:       89 44 24 2c             mov    %eax,0x2c(%esp)
         :           memcpy(&tv_end, &tv_now, sizeof(tv_now));
         :           tv_end.tv_sec += strtol(argv[1], NULL, 10);
         :           while (tv_now.tv_sec < tv_end.tv_sec ||
         :                  tv_now.tv_usec < tv_end.tv_usec) {
         :                   count = 0;
         :                   while (count < 100000000UL)
   14.78 :    804853d:       8b 44 24 2c             mov    0x2c(%esp),%eax
   56.23 :    8048541:       3d ff e0 f5 05          cmp    $0x5f5e0ff,%eax
    0.00 :    8048546:       76 ea                   jbe    8048532 <main+0xae>
[...]

コードをコンパイルするとき-fno-omit-frame-pointerは、フラグとフラグを渡すことを忘れないでください。-ggdb

于 2013-10-17T23:37:57.367 に答える
5

プログラムに関数がほとんどなく、システム関数やI / Oを呼び出すことはほとんどない場合を除いて、プログラムカウンターをサンプリングするプロファイラーは、あなたが発見しているように、多くのことを教えてくれません。実際、よく知られているプロファイラーgprofは、自己時間のみのプロファイリングの無用さに対処するために特別に作成されました(成功したわけではありません)。

実際に機能するのは、コールスタックをサンプリングし(これにより、呼び出しがどこから来ているかを検出し)、実時間(I / O時間を含む)でレポートし、行または命令によってレポートします(これにより、関数呼び出しを特定します。彼らが住んでいる機能だけでなく、調査する必要があります)。

さらに、検索する必要のある統計は、スタック上の時間の割合であり、呼び出しの数ではなく、平均包括関数時間ではありません。特に「セルフタイム」ではありません。 呼び出し命令(または非呼び出し命令)が38%の確率でスタックにある場合、それを取り除くことができれば、どれだけ節約できますか?38%! とても簡単ですよね?

このようなプロファイラーの例はZoomです。

この主題に関して理解されるべきより多くの問題があります。

追加:@cafは私にperf情報を探しさせてくれました、そしてあなたがコマンドライン引数を含めたので-gそれはスタックサンプルを収集します。次に、コールツリーレポートを取得できます。次に、実時間でサンプリングしていることを確認すると(CPU時間だけでなく待機時間も取得できます)、必要なものがほぼ揃っています。

于 2011-08-11T20:09:28.557 に答える