GNU/Linux >> Linux の 問題 >  >> Linux

Linux アプリケーションのプロファイリング

<ブロック引用>

理想的には、プロセスにアタッチし、次の定期的なスナップショットをログに記録するアプリケーションが必要です:

  • メモリ使用量
  • スレッド数
  • CPU 使用率

プロセスに関するこの種の情報を収集するために、Linux ではプロファイラーは実際には必要ありません。

<オール>
  • top を使用できます バッチモードで。強制終了されるか、N 回の反復が完了するまで、バッチ モードで実行されます。

    top -b -p `pidof a.out`
    

    また

    top -b -p `pidof a.out` -n 100
    

    これを取得します:

    $ top -b -p `pidof a.out`
    
    top - 10:31:50 up 12 days, 19:08,  5 users,  load average: 0.02, 0.01, 0.02
    Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
    Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Mem:  16330584k total,  2335024k used, 13995560k free,   241348k buffers
    Swap:  4194296k total,        0k used,  4194296k free,  1631880k cached
    
      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
    24402 SK        20   0 98.7m 1056  860 S 43.9  0.0   0:11.87 a.out
    
    
    top - 10:31:53 up 12 days, 19:08,  5 users,  load average: 0.02, 0.01, 0.02
    Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
    Cpu(s):  0.9%us,  3.7%sy,  0.0%ni, 95.5%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Mem:  16330584k total,  2335148k used, 13995436k free,   241348k buffers
    Swap:  4194296k total,        0k used,  4194296k free,  1631880k cached
    
    PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
    24402 SK      20   0 98.7m 1072  860 S 19.0  0.0   0:12.44 a.out
    
  • ps を使用できます (たとえば、シェル スクリプトで)

    ps --format pid,pcpu,cputime,etime,size,vsz,cmd -p `pidof a.out`
    
    <ブロック引用>

    Linux マシンでアプリケーションのパフォーマンスを記録する手段が必要です

    これを行うには、 perf を使用する必要があります Linux カーネルが 2.6.32 より大きい場合、または OProfile が古い場合。どちらのプログラムも、プログラムをインストルメント化する必要はありません (Gprof が必要とするように)。ただし、perf でコールグラフを正しく取得するには -fno-omit-frame-pointer を使用してプログラムをビルドする必要があります。例:g++ -fno-omit-frame-pointer -O2 main.cpp .

  • Linux perf に関しては :

    <オール>
  • パフォーマンス データを記録するには:

    perf record -p `pidof a.out`
    

    または 10 秒間記録するには:

    perf record -p `pidof a.out` sleep 10
    

    またはコールグラフで記録する ()

    perf record -g -p `pidof a.out`
    
  • 記録されたデータを分析するには

    perf report --stdio
    perf report --stdio --sort=dso -g none
    perf report --stdio -g none
    perf report --stdio -g
    

    RHEL 6.3 では /boot/System.map-2.6.32-279.el6.x86_64 の読み取りが許可されているため、通常は --kallsyms=/boot/System.map-2.6.32-279.el6.x86_64 を追加します。パフォーマンス レポートの作成:

    perf report --stdio -g --kallsyms=/boot/System.map-2.6.32-279.el6.x86_64
    
    ここでは、Linux の「perf」の使用に関する詳細情報をいくつか書きました。

    まず第一に、これは perf を使用した Linux プロファイリングに関するチュートリアルです

    perf を使用できます Linux カーネルが 2.6.32 より大きい場合、または OProfile が古い場合。どちらのプログラムも、プログラムをインストルメント化する必要はありません (Gprof が必要とするように)。ただし、perf でコール グラフを正しく取得するには -fno-omit-frame-pointer でプログラムをビルドする必要があります .例:g++ -fno-omit-frame-pointer -O2 main.cpp .

    perf top を使用して、アプリケーションの「ライブ」分析を確認できます :

     sudo perf top -p `pidof a.out` -K
    
  • または、実行中のアプリケーションのパフォーマンス データを記録し、その後分析することもできます。

    <オール>
  • パフォーマンス データを記録するには:

    perf record -p `pidof a.out`
    

    または 10 秒間記録するには:

    perf record -p `pidof a.out` sleep 10
    

    またはコールグラフで記録する ()

    perf record -g -p `pidof a.out`
    
  • 記録されたデータを分析するには

  • perf report --stdio
    perf report --stdio --sort=dso -g none
    perf report --stdio -g none
    perf report --stdio -g
    

    または、この方法でアプリケーションを起動して終了するのを待つだけで、アプリケーションのパフォーマンス データを記録し、その後分析することができます。

    perf record ./a.out
    

    これは、テスト プログラムのプロファイリングの例です。

    テスト プログラムはファイル main.cpp にあります (main.cpp 回答の一番下にあります):

    このようにコンパイルします:

    g++ -m64 -fno-omit-frame-pointer -g main.cpp -L.  -ltcmalloc_minimal -o my_test
    

    -fno-omit-frame-pointer でコンパイルされているため、libc malloc はこのオプションなしでコンパイルされているように見えるため、libmalloc_minimial.so を使用します。次に、テスト プログラムを実行します。

    ./my_test 100000000
    

    次に、実行中のプロセスのパフォーマンス データを記録します。

    perf record -g  -p `pidof my_test` -o ./my_test.perf.data sleep 30
    

    次に、モジュールごとの負荷を分析します:

    perf report --stdio -g none --sort comm,dso -i ./my_test.perf.data
    
    # Overhead  Command                 Shared Object
    # ........  .......  ............................
    #
        70.06%  my_test  my_test
        28.33%  my_test  libtcmalloc_minimal.so.0.1.0
         1.61%  my_test  [kernel.kallsyms]
    

    次に、関数ごとの負荷が分析されます:

    perf report --stdio -g none -i ./my_test.perf.data | c++filt
    
    # Overhead  Command                 Shared Object                       Symbol
    # ........  .......  ............................  ...........................
    #
        29.30%  my_test  my_test                       [.] f2(long)
        29.14%  my_test  my_test                       [.] f1(long)
        15.17%  my_test  libtcmalloc_minimal.so.0.1.0  [.] operator new(unsigned long)
        13.16%  my_test  libtcmalloc_minimal.so.0.1.0  [.] operator delete(void*)
         9.44%  my_test  my_test                       [.] process_request(long)
         1.01%  my_test  my_test                       [.] operator delete(void*)@plt
         0.97%  my_test  my_test                       [.] operator new(unsigned long)@plt
         0.20%  my_test  my_test                       [.] main
         0.19%  my_test  [kernel.kallsyms]             [k] apic_timer_interrupt
         0.16%  my_test  [kernel.kallsyms]             [k] _spin_lock
         0.13%  my_test  [kernel.kallsyms]             [k] native_write_msr_safe
    
         and so on ...
    

    次に、呼び出しチェーンが分析されます:

    perf report --stdio -g graph -i ./my_test.perf.data | c++filt
    
    # Overhead  Command                 Shared Object                       Symbol
    # ........  .......  ............................  ...........................
    #
        29.30%  my_test  my_test                       [.] f2(long)
                |
                --- f2(long)
                   |
                    --29.01%-- process_request(long)
                              main
                              __libc_start_main
    
        29.14%  my_test  my_test                       [.] f1(long)
                |
                --- f1(long)
                   |
                   |--15.05%-- process_request(long)
                   |          main
                   |          __libc_start_main
                   |
                    --13.79%-- f2(long)
                              process_request(long)
                              main
                              __libc_start_main
    
        15.17%  my_test  libtcmalloc_minimal.so.0.1.0  [.] operator new(unsigned long)
                |
                --- operator new(unsigned long)
                   |
                   |--11.44%-- f1(long)
                   |          |
                   |          |--5.75%-- process_request(long)
                   |          |          main
                   |          |          __libc_start_main
                   |          |
                   |           --5.69%-- f2(long)
                   |                     process_request(long)
                   |                     main
                   |                     __libc_start_main
                   |
                    --3.01%-- process_request(long)
                              main
                              __libc_start_main
    
        13.16%  my_test  libtcmalloc_minimal.so.0.1.0  [.] operator delete(void*)
                |
                --- operator delete(void*)
                   |
                   |--9.13%-- f1(long)
                   |          |
                   |          |--4.63%-- f2(long)
                   |          |          process_request(long)
                   |          |          main
                   |          |          __libc_start_main
                   |          |
                   |           --4.51%-- process_request(long)
                   |                     main
                   |                     __libc_start_main
                   |
                   |--3.05%-- process_request(long)
                   |          main
                   |          __libc_start_main
                   |
                    --0.80%-- f2(long)
                              process_request(long)
                              main
                              __libc_start_main
    
         9.44%  my_test  my_test                       [.] process_request(long)
                |
                --- process_request(long)
                   |
                    --9.39%-- main
                              __libc_start_main
    
         1.01%  my_test  my_test                       [.] operator delete(void*)@plt
                |
                --- operator delete(void*)@plt
    
         0.97%  my_test  my_test                       [.] operator new(unsigned long)@plt
                |
                --- operator new(unsigned long)@plt
    
         0.20%  my_test  my_test                       [.] main
         0.19%  my_test  [kernel.kallsyms]             [k] apic_timer_interrupt
         0.16%  my_test  [kernel.kallsyms]             [k] _spin_lock
         and so on ...
    

    したがって、この時点で、プログラムがどこで時間を費やしているかがわかります。

    これが main.cpp です テスト用ファイル:

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    time_t f1(time_t time_value)
    {
      for (int j = 0; j < 10; ++j) {
        ++time_value;
        if (j%5 == 0) {
          double *p = new double;
          delete p;
        }
      }
      return time_value;
    }
    
    time_t f2(time_t time_value)
    {
      for (int j = 0; j < 40; ++j) {
        ++time_value;
      }
      time_value = f1(time_value);
      return time_value;
    }
    
    time_t process_request(time_t time_value)
    {
      for (int j = 0; j < 10; ++j) {
        int *p = new int;
        delete p;
        for (int m = 0; m < 10; ++m) {
          ++time_value;
        }
      }
      for (int i = 0; i < 10; ++i) {
        time_value = f1(time_value);
        time_value = f2(time_value);
      }
      return time_value;
    }
    
    int main(int argc, char* argv2[])
    {
      int number_loops = argc > 1 ? atoi(argv2[1]) : 1;
      time_t time_value = time(0);
      printf("number loops %d\n", number_loops);
      printf("time_value: %d\n", time_value);
    
      for (int i = 0; i < number_loops; ++i) {
        time_value = process_request(time_value);
      }
      printf("time_value: %ld\n", time_value);
      return 0;
    }
    

    Linus Torvalds 自身の引用:

    <ブロック引用>

    gprof を使用しないでください。あなたはかなり 新しい Linux 'perf' ツールを使用する方がよいでしょう。

    そして後で...

    <ブロック引用>

    一度使い始めたら、gprof や oprofile を二度と使うことはないでしょう。

    Re:[PATCH] grep:skip-worktree エントリに対して外部 grep を実行しないを参照してください (2010-01-04)


    Linux
    1. Linuxでアプリケーションの起動時間を改善する方法

    2. Linux で Java アプリケーションをサービスとして実行する

    3. Linuxで起動アプリケーションのリストを取得する

    1. Linux – LinuxでTlbミスを測定するコマンド?

    2. Linux – Slackware 13.1にPerfをインストールできませんか?

    3. Linux のメモリ不足のアプリケーション ティアダウンを回避する

    1. LinuxにSpotifyアプリケーションをインストールする方法

    2. Linux –カレンダーに使用するアプリケーションはどれですか?

    3. Linux アプリケーションの syscall アクセスを制限する