GNU/Linux >> Belajar Linux >  >> Linux

Pembuatan profil aplikasi Linux

Idealnya, saya memerlukan aplikasi yang akan dilampirkan ke proses dan mencatat snapshot berkala dari:

  • penggunaan memori
  • jumlah utas
  • Penggunaan CPU

Nah, untuk mengumpulkan jenis informasi tentang proses Anda, Anda sebenarnya tidak memerlukan profiler di Linux.

  1. Anda dapat menggunakan top dalam mode batch. Ini berjalan dalam mode batch sampai dimatikan atau sampai N iterasi selesai:

    top -b -p `pidof a.out`
    

    atau

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

    dan Anda akan mendapatkan ini:

    $ 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
    
  2. Anda dapat menggunakan ps (misalnya dalam skrip Shell)

    ps --format pid,pcpu,cputime,etime,size,vsz,cmd -p `pidof a.out`
    

    Saya memerlukan beberapa cara untuk merekam kinerja aplikasi di mesin Linux

    Untuk melakukan ini, Anda perlu menggunakan perf jika kernel Linux Anda lebih besar dari 2.6.32 atau OProfile jika lebih tua. Kedua program tidak mengharuskan Anda untuk melengkapi program Anda (seperti yang dibutuhkan Gprof). Namun, untuk mendapatkan grafik panggilan dengan benar di perf Anda perlu membangun program Anda dengan -fno-omit-frame-pointer. Misalnya:g++ -fno-omit-frame-pointer -O2 main.cpp .

Sedangkan untuk Linux perf :

  1. Untuk merekam data performa:

    perf record -p `pidof a.out`
    

    atau untuk merekam selama 10 detik:

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

    atau untuk merekam dengan grafik panggilan ()

    perf record -g -p `pidof a.out`
    
  2. Untuk menganalisis data yang direkam

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

    Pada RHEL 6.3 diperbolehkan untuk membaca /boot/System.map-2.6.32-279.el6.x86_64, jadi saya biasanya menambahkan --kallsyms=/boot/System.map-2.6.32-279.el6.x86_64 saat melakukan laporan kinerja:

    perf report --stdio -g --kallsyms=/boot/System.map-2.6.32-279.el6.x86_64
    
    Di sini saya menulis beberapa informasi lebih lanjut tentang penggunaan Linux `perf`:

    Pertama-tama - ini adalah tutorial tentang pembuatan profil Linux dengan perf

    Anda dapat menggunakan sempurna jika Kernel Linux Anda lebih besar dari 2.6.32 atau OProfile jika lebih tua. Kedua program tidak mengharuskan Anda untuk melengkapi program Anda (seperti yang dibutuhkan Gprof). Namun, untuk mendapatkan grafik panggilan dengan benar di perf Anda perlu membuat program dengan -fno-omit-frame-pointer . Misalnya:g++ -fno-omit-frame-pointer -O2 main.cpp .

    Anda dapat melihat analisis "langsung" dari aplikasi Anda dengan perf top :

     sudo perf top -p `pidof a.out` -K
    

Atau Anda dapat merekam data kinerja aplikasi yang sedang berjalan dan menganalisisnya setelah itu:

  1. Untuk merekam data performa:

    perf record -p `pidof a.out`
    

    atau untuk merekam selama 10 detik:

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

    atau untuk merekam dengan grafik panggilan ()

    perf record -g -p `pidof a.out`
    
  2. Untuk menganalisis data yang direkam

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

Atau Anda dapat merekam data performa aplikasi dan menganalisisnya setelah itu hanya dengan meluncurkan aplikasi dengan cara ini dan menunggu hingga keluar:

perf record ./a.out

Ini adalah contoh pembuatan profil program pengujian.

Program pengujian ada di file main.cpp (main.cpp ada di bagian bawah jawaban):

Saya mengkompilasinya dengan cara ini:

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

Saya menggunakan libmalloc_minimial.so karena dikompilasi dengan -fno-omit-frame-pointer sementara libc malloc tampaknya dikompilasi tanpa opsi ini. Kemudian saya menjalankan program pengujian saya:

./my_test 100000000

Lalu saya merekam data kinerja dari proses yang sedang berjalan:

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

Kemudian saya menganalisis beban per modul:

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]

Kemudian muat per fungsi dianalisis:

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 ...

Kemudian rantai panggilan dianalisis:

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 ...

Jadi pada titik ini Anda tahu di mana program Anda menghabiskan waktu.

Dan ini adalah main.cpp file untuk pengujian:

#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;
}

Mengutip Linus Torvalds sendiri:

Jangan gunakan gprof. Kamu banyak lebih baik menggunakan alat 'perf' Linux yang agak baru.

Dan nanti ...

Saya dapat menjamin bahwa begitu Anda mulai menggunakannya, Anda tidak akan pernah menggunakan gprof atau oprofile lagi.

Lihat Re:[PATCH] grep:jangan lakukan grep eksternal pada entri skip-worktree (2010-01-04)


Linux
  1. Membatasi akses syscall untuk aplikasi Linux

  2. Bagaimana cara menandatangani aplikasi Mac OS X di Linux?

  3. Hindari pembongkaran aplikasi kehabisan memori linux

  1. Cara Meningkatkan Waktu Startup Aplikasi Di Linux

  2. Cara menginstal aplikasi Spotify di Linux

  3. Linux – Perintah Untuk Mengukur Tlb Misses Di Linux?

  1. Linux – Aplikasi Mana yang Digunakan Untuk Kalender?

  2. Linux – Gagal Menginstal Perf Pada Slackware 13.1?

  3. Jalankan Aplikasi Java sebagai Layanan di Linux