Процесс с 1% загрузкой ЦП, приводящий к средней нагрузке 1,5

Процесс с 1% загрузкой ЦП, приводящий к средней нагрузке 1,5

Недавно мы наблюдали высокую среднюю нагрузку около 1,5 на нашей встроенной системе, хотя практически все процессы предположительно находятся в спящем режиме (согласно htop).

Система, о которой идет речь, представляет собой двухъядерный Cortex-A9, работающий под управлением ядра Linux в реальном времени (4.14.126), собранного с помощью buildroot. Мы используем initramfs для нашей корневой файловой системы, и у нас нет подкачки, поэтому определенно естьнет дискового ввода-выводапри нормальной работе.

После небольшого исследования мы выяснили, что нагрузка вызвана программой под названиемswupdate, который предоставляет нам удобный веб-интерфейс для обновления программного обеспечения (и мы бы очень хотели продолжать его использовать).

Когда я использую timeдля оценки среднего использования процессора этим приложением (путем вычисления(пользователь+система)/реальный), я получаю значение всего около 1%, что не имеет особого смысла, учитывая среднюю нагрузку 1,5.

Я знаю, что средняя загрузка также включает процессы в TASK_UNINTERRUPTIBLEсостоянии, которые не способствуют использованию процессора. Я не понимаю, почему какой-либо из потоков/процессов этого приложения когда-либо будет в этом состоянии.

Для дальнейшего анализа ситуации я записал трассировку ядра с помощьюlttng, что показывает, что единственное, что делает swupdate, это (каждые 50 мс): введите описание изображения здесь

и это (каждые 100 мс): введите описание изображения здесь

Как вы можете видеть, есть немного того, что похоже на IPC на основе сокетов, и выбор ожиданиячто-нибудь. В случае IPC один поток, по-видимому, в основном блокирует nanosleep(), а другой блокирует accept(), и ни один из них не должен потреблять системные ресурсы, насколько мне известно.

К вашему сведению: временная база для обоих снимков экрана одинакова, а IPC занимает в общей сложности около 500-600 мкс (что, учитывая интервал в 50 мс, вполне соответствует наблюдаемому 1% использованию ЦП).

Так что же здесь является причиной нагрузки?

решение1

Поскольку задачи в состоянии R и D вносят вклад в нагрузку Linux, вы можете сделать выборку всех потоков в вашей системе в любом из этих состояний. Например:

for x in {1..100} ; do ps -aeos,user,comm,wchan | grep "^[RD]" ; sleep 0.1 ; done | sort | uniq -c | sort -nbr | head -20

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

# for x in {1..100} ; do
>   ps -aeos,user,comm,wchan | grep "^[RD]"
>   sleep 0.1
> done | sort | uniq -c | sort -nbr | head -20

    100 R root     ps              -
      3 R oracle   oracle_14047_li -
      2 R root     rcu_sched       rcu_gp_kthread
      2 R root     rcu_sched       -
      2 R root     kworker/1:2-eve -
      2 R oracle   perl            -
      2 R oracle   ora_vktm_lin19c hrtimer_nanosleep
      2 D root     md10_raid10     md_super_wait
      2 D oracle   ora_ckpt_linprd md_write_start
      1 R redis    redis-server    -
      1 R oracle   ora_vktm_linprd hrtimer_nanosleep
      1 R oracle   ora_m001_linprd -
      1 D root     xfsaild/dm-18   rq_qos_wait
      1 D oracle   ora_mz00_lin19c x64_sys_io_destroy
      1 D oracle   ora_lg00_lin19c inode_dio_wait
      1 D oracle   ora_dbrm_lin19c msleep

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

Вы можете пойти глубже (но не с ps), вы можете сделать выборку /proc/PID/syscallи /proc/PID/stackполучить информацию о системных вызовах и трассировке стека ядра. Я написал инструмент под названием Linux Process Snapper ( psn) для этого, так что вы можете сделать довольно продвинутую детализацию таких проблем производительности, не прибегая к трассировке ядра:

[tanel@linux01 ~]$ sudo psn -G syscall,wchan

Linux Process Snapper v0.18 by Tanel Poder [https://0x.tools]
Sampling /proc/syscall, stat, wchan for 5 seconds... finished.


=== Active Threads ==========================================================================================

 samples | avg_threads | comm             | state                  | syscall         | wchan                 
-------------------------------------------------------------------------------------------------------------
     511 |      255.50 | (kworker/*:*)    | Disk (Uninterruptible) | [kernel_thread] | blkdev_issue_flush 
     506 |      253.00 | (oracle_*_l)     | Disk (Uninterruptible) | pread64         | do_blockdev_direct_IO 
      28 |       14.00 | (oracle_*_l)     | Running (ON CPU)       | [running]       | 0                     
       1 |        0.50 | (collectl)       | Running (ON CPU)       | [running]       | 0                     
       1 |        0.50 | (mysqld)         | Running (ON CPU)       | [running]       | 0                     
       1 |        0.50 | (ora_lgwr_lin*c) | Disk (Uninterruptible) | io_submit       | inode_dio_wait        
       1 |        0.50 | (oracle_*_l)     | Disk (Uninterruptible) | pread64         | 0                     
       1 |        0.50 | (oracle_*_l)     | Running (ON CPU)       | [running]       | SYSC_semtimedop       
       1 |        0.50 | (oracle_*_l)     | Running (ON CPU)       | [running]       | read_events           
       1 |        0.50 | (oracle_*_l)     | Running (ON CPU)       | read            | 0                     
       1 |        0.50 | (oracle_*_l)     | Running (ON CPU)       | semtimedop      | SYSC_semtimedop       

Вы можете пойти гораздо дальше, соответствующая запись в блоге находится здесь:

решение2

Использование ЦП и загрузка — разные показатели. Фактически загрузка может быть выше 1. ЦП — это реальное время, используемое ЦП, поэтому оно всегда должно быть меньше 100% (но на многоядерных/ЦП, но вы поняли идею). Загрузка показывает загрузку: сколько процессов запущено и ожидает запуска.

Как вы, вероятно, знаете (из обсуждения в вашем вопросе), ввод-вывод обычно является одним из таких ожиданий, поэтому он увеличивает нагрузку. Но у вас также могут быть сигналы/семафоры/блокировки, которые могут вызвать ожидание, и они могут быть вызваны только одним процессом, который не выполняет ввод-вывод). Например, если один процесс просыпается каждую секунду, и есть много процессов, которые ждут данных от такого процесса, вы получаете более высокую нагрузку (равную количеству ожидающих процессов).

Вы можете видеть каналы как ввод-вывод, но mmap и блокировки... вы классифицируете как ввод-вывод? Они не будут отображаться в bio (блок ввода-вывода), поэтому вы можете не увидеть их во многих статистиках нагрузки.

Часто более простой способ узнать это: заблокировать процесс и проверить, где он находится. Сделайте это много раз, и вы, как можно надеяться, увидите, что одна функция блокируется (и вы можете обнаружить это гораздо чаще, чем другие функции).

решение3

У меня возникла та же проблема на встраиваемой системе, работающей на i.mx28 на частоте примерно 450 МГц.

htopпостоянно отображалась загрузка ЦП на 50%, вызванная исключительно одной из swupdateзадач.

При просмотре mongoose_interface.cвашего 100-мс наблюдения, сработавшего при прочтении этого в конце start_mongoose():

                mg_mgr_poll(&mgr, 100);

Я экспериментально изменил 100 на 1000, и после перекомпиляции и перезапуска загрузка ЦП снизилась примерно до 2% потоков, swupdateкак и наблюдалось в htop.

Как я уже сказал, это было экспериментально, так как цифры показались мне слишком уж похожими на совпадения. Я не исследовал, возникают ли какие-либо побочные эффекты.

Связанный контент