Назад | Перейти на главную страницу

Мониторинг системного процессора / системных вызовов в Linux

У меня есть пара процессов, которые потребляют много системного процессорного времени (как определено с помощью vmstat). Есть ли простой способ узнать, какие системные вызовы выполняются?

Я знаю, что есть strace, но есть ли способ быстрее и проще? Есть ли что-то вроде "топа" для системных вызовов?

Я думаю, что с -c flag, наверное, самый близкий из известных мне. Если вы не использовали -c флаг, попробуйте это:

$  sudo strace -c -p 12345

Где 12345 - это идентификатор процесса (PID) рассматриваемого процесса. Обратите внимание, что отслеживание процесса добавляет дополнительные накладные расходы, поэтому, пока вы его отслеживаете, процесс будет работать медленнее.

После того, как вы запустите это столько, сколько хотите собирать данные, нажмите Ctrl-C чтобы остановить сбор данных и вывести результаты. Результат будет примерно таким:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 31.88    0.001738         145        12           futex
 16.79    0.000915          11        80           tgkill
 12.36    0.000674          34        20           read
  9.76    0.000532         266         2           statfs
  8.42    0.000459          13        35           time
  4.38    0.000239           6        40           gettimeofday
  3.65    0.000199           4        48           sigprocmask
  2.94    0.000160          18         9           open
  2.88    0.000157          12        13           stat64
  1.32    0.000072           9         8           munmap
  0.90    0.000049           6         8           mmap2
  0.88    0.000048           3        14         7 sigreturn
  0.79    0.000043           5         9           close
  0.77    0.000042           4        10           rt_sigprocmask
  0.64    0.000035           3        12           setitimer
  0.55    0.000030           5         6         6 rt_sigsuspend
  0.53    0.000029           4         8           fstat64
  0.29    0.000016           8         2           setresuid32
  0.13    0.000007           4         2           _llseek
  0.09    0.000005           3         2           prctl
  0.04    0.000002           2         1           geteuid32
------ ----------- ----------- --------- --------- ----------------
100.00    0.005451                   341        13 total

Как видите, это разбивка всех системных вызовов, выполненных приложением, отсортированных по общему времени, включая среднее время на вызов и количество вызовов для каждого системного вызова. Если вы хотите отсортировать их по-другому, см. Страницу руководства по strace, так как есть несколько вариантов.

Я обычно использую следующие переключатели strace.

strace -ffttT -p pid -o /tmp/strace.out

Пример этого может выглядеть так:

19:35:57.485493 mprotect(0x7f35e7472000, 16384, PROT_READ) = 0 <0.000037>
19:35:57.485599 mprotect(0x7f35e7692000, 4096, PROT_READ) = 0 <0.000030>
19:35:57.485697 mprotect(0x7f35e78b7000, 4096, PROT_READ) = 0 <0.000030>
19:35:57.485782 munmap(0x7f35e7896000, 129588) = 0 <0.000037>
19:35:57.485875 set_tid_address(0x7f35e78949d0) = 10730 <0.000029>
19:35:57.485960 set_robust_list(0x7f35e78949e0, 0x18) = 0 <0.000024>
19:35:57.486048 futex(0x7fff8f58628c, FUTEX_WAKE_PRIVATE, 1) = 0 <0.000025>
19:35:57.486131 futex(0x7fff8f58628c, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1,       NULL, 7f35e7894700) = -1 EAGAIN (Resource temporarily unavailable) <0.000024>

Вы видите разницу во времени в правой части системного вызова, показывающую, сколько времени потребовалось для перехода от одного системного вызова к другому.

Он уловит разницу во времени между системными вызовами. Итак, когда вы видите, что системный вызов имеет промежуток в несколько секунд до следующего системного вызова, значит, он издает некоторый шум.

Другой метод - это создание ядра с помощью gcore. Однако для этого требуется небольшой опыт навигации по GDB.

Но, если поток является потоком ядра, вы не можете его объединить или создать ядро. В этом случае мы должны использовать что-то более сложное. В ядре RHEL5 мы используем oprofile. В RHEL6 мы используем perf. Я предпочитаю перфоманс опрофиле. Данные производительности могут быть собраны в графическом формате, показывающем системный вызов, в котором используется максимальный процент ЦП.

С тестовой перфомансой я это вижу.

38.06%  swapper  [kernel.kallsyms]  [k] mwait_idle_with_hints                                                                                                               ↑

29.45%  swapper  [kernel.kallsyms]  [k] read_hpet 
4.90%  swapper  [kernel.kallsyms]  [k] acpi_os_read_port                                                                                                                   ▒
4.74%  swapper  [kernel.kallsyms]  [k] hpet_next_event   

Он показывает функцию ядра, на которую тратится 38% процессорного времени. Теперь мы можем проверить функцию и посмотреть, что она делает и что должна делать.

На нескольких примерах это не так уж и сложно.

Возможно, попробуйте один из профилировщиков выборки, например oprofile, или для более новых ядер perf. Если вам повезет, «perf top» может сказать вам именно то, что вы хотите. Видеть вот несколько примеров