Профилирование приложения Linux

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

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

Какие-либо идеи?

35
задан MalcomTucker 9 February 2010 в 13:29
поделиться

5 ответов

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

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

7
ответ дан 27 November 2019 в 06:48
поделиться

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

"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

Удачи!

21
ответ дан 27 November 2019 в 06:48
поделиться

В идеале, мне нужно приложение, которое будет прикреплять к процессу и записывать в журнал периодические снимки: количество используемых потоков памяти, количество используемых 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 (например, в сценарии командной строки)

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

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

Для этого нужно использовать perf, если ваш Linux Kernal больше 2.6.32, или Oprofile, если он старше. Обе программы не требуют от вас инструктировать вашу программу (как требует gporf). Однако для того, чтобы ger вызывал граф корректно в perf, вам необходимо собрать программу с указателем -fno-omit-frame. Например: 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 отчёт:

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). Однако, чтобы получить граф вызовов в perf правильно, Вам необходимо собрать Вашу программу с помощью -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, в то время как 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;
}
47
ответ дан 27 November 2019 в 06:48
поделиться

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

2
ответ дан 27 November 2019 в 06:48
поделиться

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

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

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

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

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

3
ответ дан 27 November 2019 в 06:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: