簡體   English   中英

Linux 應用程序分析

[英]Linux application profiling

我需要一些方法來記錄 Linux 機器上應用程序的性能。 我不會有 IDE。

理想情況下,我需要一個應用程序,該應用程序將附加到進程並記錄以下定期快照: 內存使用情況 線程數 CPU 使用情況

有任何想法嗎?

理想情況下,我需要一個應用程序,該應用程序將附加到進程並記錄以下定期快照: 內存使用情況 線程數 CPU 使用情況

好吧,為了收集有關您的進程的此類信息,您實際上並不需要 Linux 上的分析器。
1) 您可以在批處理模式下使用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

2)您可以使用ps (例如在shell腳本中)

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

我需要一些方法來記錄 Linux 機器上的應用程序的性能

為此,如果您的 Linux 內核大於 2.6.32,您需要使用perf ,如果它更舊,則需要使用 Oprofile。 這兩個程序都不需要您對程序進行指導(如gporf需要)。 但是,為了在perf正確調用圖,您需要使用 -fno-omit-frame-pointer 構建程序。 例如: g++ -fno-omit-frame-pointer -O2 main.cpp

至於Linux的perf

1) 記錄性能數據:

perf record -p `pidof a.out`

或錄制 10 秒:

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

或用調用圖記錄 ()

perf record -g -p `pidof a.out` 

2) 分析記錄的數據

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 分析的教程

如果您的 Linux 內核大於 2.6.32,您可以使用 perf,如果它更舊,您可以使用 oprofile。 這兩個程序都不需要您對程序進行檢測(如 gprof 需要)。 但是,為了在 perf 中正確獲取調用圖,您需要使用-fno-omit-frame-pointer構建程序。 例如: g++ -fno-omit-frame-pointer -O2 main.cpp 您可以使用 perf top 查看您的應用程序的“實時”分析:

perf record -p `pidof a.out`

或者,您可以記錄正在運行的應用程序的性能數據,然后對其進行分析: 1) 記錄性能數據:

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

或錄制 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

2) 分析記錄的數據

perf record ./a.out

或者您可以記錄應用程序的性能數據並在此之后分析它們,只需以這種方式啟動應用程序並等待它退出:

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

這是分析測試程序的示例 測試程序在文件 main.cpp 中(我將把 main.cpp 放在消息的底部): 我是這樣編譯的:

./my_test 100000000 

我使用 libmalloc_minimial.so 因為它是用 -fno-omit-frame-pointer 編譯的,而 libc malloc 似乎是在沒有這個選項的情況下編譯的。 然后我運行我的測試程序

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

然后分析調用鏈:

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

所以在這一點上你知道你的程序在哪里花費時間。 這是用於測試的 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 本人的話:

"Don't use gprof. You're _much_ better off using the newish Linux 'perf' tool."

然后 ...

"I can pretty much guarantee that once you start using it, you'll never use gprof or oprofile again."

參見: http : //marc.info/?l=git&m=126262088816902&w=2

祝你好運!

如果您正在尋找可能加速程序的事情,您需要stackshots 一個簡單的方法是使用pstack實用程序,或者lsstack如果可以的話。

你可以做得比gprof更好。 如果您想使用官方分析工具,您需要一些能夠在掛鍾時間對調用堆棧進行采樣並呈現行級成本的東西,例如 Oprofile 或 RotateRight/Zoom。

您可以使用valgrind 它將數據記錄在一個文件中,您可以稍后使用適當的 gui(如KCacheGrind)進行分析

一個使用示例是:

valgrind --tool=callgrind --dump-instr=yes --simulate-cache=yes your_program

它將生成一個名為callgrind.out.xxx的文件,其中 xxx 是程序的 pid

編輯:與 gprof 不同,valgrind 可以使用許多不同的語言,包括有一些限制的java。

你研究過gprof嗎? 您需要使用 -pg 選項編譯代碼,該選項用於檢測代碼。 之后,您可以運行該程序並使用 gprof 查看結果。

https://en.wikipedia.org/wiki/Gprof

你也可以試試cpuprofiler.com 它獲取您通常從 top 命令獲取的信息,甚至可以從 Web 瀏覽器遠程查看 CPU 使用情況數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM