Профилирование приложений Linux - PullRequest
35 голосов
/ 09 февраля 2010

Мне нужны средства записи производительности приложения на компьютере с Linux. У меня не будет IDE.

В идеале мне нужно приложение, которое будет подключаться к процессу и регистрировать периодические снимки: использование памяти количество потоков Загрузка процессора

Есть идеи?

Ответы [ 6 ]

46 голосов
/ 09 февраля 2010

В идеале мне нужно приложение, которое будет подключаться к процессу и регистрировать периодические снимки: использования памяти, количества потоков, загрузки ЦП

Что ж, для того, чтобы собирать такую ​​информацию о вашем процессе, вам на самом деле не нужен профилировщик в 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 (например, в скрипте оболочки)

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

Мне нужны средства записи производительности приложения на компьютере с Linux

Для этого вам нужно использовать perf, если ваш Linux Kernal больше 2.6.32, или 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:

Прежде всего - это учебник по профилированию Linux с perf

Вы можете использовать perf, если ядро ​​Linux более 2.6.32, или oprofile, если оно старше. Обе программы не требуют от вас инструментирования вашей программы (как требует gprof). Однако для корректного отображения графа вызовов в программе вам нужно собрать программу с -fno-omit-frame-pointer. Например: g++ -fno-omit-frame-pointer -O2 main.cpp. Вы можете увидеть «живой» анализ вашего приложения с помощью perf top:

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

Или вы можете записать данные о производительности запущенного приложения и проанализировать их после этого: 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

Или вы можете записать данные о производительности приложения и проанализировать их после этого, просто запустив приложение таким образом и ожидая его выхода:

perf record ./a.out

Это пример профилирования тестовой программы Тестовая программа находится в файле main.cpp (я поставлю main.cpp внизу сообщения): Я компилирую это так:

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

Я использую libmalloc_minimial.so, так как он компилируется с -fno-omit-frame-pointer, тогда как libc malloc, кажется, компилируется без этой опции. Затем я запускаю свою тестовую программу

./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;
}
20 голосов
/ 09 февраля 2010

Цитируя самого Линуса Торвальдса:

"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

Удачи!

7 голосов
/ 09 февраля 2010

Если вы ищете что-то, что могло бы ускорить программу, вам нужно stackshots . Простой способ сделать это - использовать утилиту pstack или lsstack , если вы можете ее получить.

Вы можете сделать лучше, чем gprof . Если вы хотите использовать официальный инструмент профилирования, вам нужно что-то, что производит выборку стека вызовов по настенным часам и представляет уровень строки стоимость, например Oprofile или RotateRight / Zoom.

3 голосов
/ 09 февраля 2010

Вы можете использовать valgrind . Он записывает данные в файл, который вы можете проанализировать позже, используя соответствующий графический интерфейс, например KCacheGrind

Пример использования:

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

Будет сгенерирован файл с именем callgrind.out.xxx, где xxx - pid программы

edit : в отличие от gprof valgrind работает со многими различными языками, включая java с некоторыми ограничениями .

2 голосов
/ 09 февраля 2010

Вы смотрели в gprof? Вам необходимо скомпилировать код с опцией -pg, которая обрабатывает код. После этого вы можете запустить проргам и использовать gprof, чтобы увидеть результаты.

1 голос
/ 14 января 2014

Вы также можете попробовать cpuprofiler.com . Он получает информацию, которую вы обычно получаете от верхней команды, а данные об использовании процессора можно даже просматривать удаленно из веб-браузера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...