CPU 使用率 1% 的进程导致平均负载为 1.5

CPU 使用率 1% 的进程导致平均负载为 1.5

我们最近观察到我们的嵌入式系统的平均负载高达 1.5 左右,尽管几乎所有进程都应该处于睡眠状态(根据htop)。

该系统是一个双核 Cortex-A9,运行使用 buildroot 构建的实时 Linux 内核 (4.14.126)。我们使用 initramfs 作为根文件系统,并且没有交换,所以肯定有无磁盘 I/O在正常操作期间。

经过一番挖掘,我们发现负载是由一个名为的程序引起的更新,它为我们提供了一个方便的软件更新网络界面(我们非常希望继续使用它)。

当我用来time估计该应用程序的平均 cpu 使用率时(通过计算(用户+系统)/真实),我得到的值只有 1% 左右,考虑到 1.5 的平均负载,这没有多大意义。

我知道平均负载还包括处于该TASK_UNINTERRUPTIBLE状态的进程,这些进程不会影响 CPU 使用率。我不明白的是为什么该应用程序的任何线程/进程都会处于该状态。

为了进一步分析情况,我使用捕获了内核跟踪LTNG,这表明 swupdate 所做的唯一事情就是(每 50 毫秒): 在此输入图像描述

这个(每 100 毫秒): 在此输入图像描述

正如你所看到的,有一些看起来是基于套接字的 IPC,并且有一个 select 正在等待某物。在 IPC 情况下,一个线程似乎主要阻塞 in nanosleep(),而另一个线程阻塞 in accept(),据我所知,这两个线程都不应该消耗任何系统资源。

仅供参考:两个屏幕截图的时基相同,IPC 大约需要 1 分钟。总共 500-600μs(考虑到 50ms 的间隔,与观察到的 1% CPU 使用率非常吻合)

那么,是什么造成了这里的负载呢?

答案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

CPU 使用率和负载是不同的指标。事实上,负载可能高于 1。CPU 是 CPU 使用的实时时间,因此它应该始终小于 100%(但在多个核心/CPU 上,但您明白了)。 Load表示负载:有多少进程正在运行和等待运行。

正如您可能知道的那样(从问题的讨论中),I/O 通常是此类等待之一,因此它会增加负载。但是您也可以拥有可能导致等待的信号/信号量/锁,而这些可能只是由一个不执行 I/O 的进程引起的。例如,如果一个进程每秒唤醒一次,并且有许多进程正在等待来自该进程的数据,则会获得更高的负载(等于等待的进程数)。

你可能将管道视为 I/O,但 mmap 和锁...你是否将其归类为 IO?它们不会出现在bio(块I/O)中,因此您可能在许多负载统计信息中看不到它们。

通常找出这一点的更简单方法是:阻止进程并检查它在哪里。多次执行此操作,您应该会看到一个函数被阻塞(并且您可能会发现它比其他函数更频繁)。

答案3

我在大约 450 MHz 的 i.mx28 上运行的嵌入式系统上遇到了同样的问题。

htop持续显示 50% CPU 使用率,这完全是由其中一项swupdate任务引起的。

当浏览mongoose_interface.c您的 100 毫秒观察时,在阅读以下内容时触发start_mongoose()

                mg_mgr_poll(&mgr, 100);

我实验性地将 100 更改为 1000,重新编译并重新启动后,CPU 使用率下降到swupdate线程的 2% 左右,如htop.

如前所述,这是实验性的,因为这些数字让我觉得太巧合了。我没有调查过是否会出现任何副作用。

相关内容