我在使用我们正在开发的某些硬件时遇到了非常奇怪的行为。我的设置包括 Linux 4.9.87,双核 iMX6 CPU 上带有 SMP 和 PREEMPT RT。
在此设置上运行的应用程序由 3 个使用 SCHED_FIFO 调度策略运行的线程组成。优先级 10、20 和 30 绑定到 CPU0。第四个线程正在 CPU1 上以相同的调度策略和 90 的优先级运行。
我遇到的行为如下:
在监视进程时,top 显示 CPU0 在 97.4% 的时间内处于空闲状态:该核心上运行的最繁忙的线程需要 8.4% - 差异为 5.8%。
这是显示 Solaris 模式下每个 CPU 和每个线程的使用情况的顶部输出:
top - 13:36:41 up 1:21, 2 users, load average: 0.52, 0.39, 0.26
Threads: 128 total, 2 running, 126 sleeping, 0 stopped, 0 zombie
%Cpu0 : 1.3 us, 1.3 sy, 0.0 ni, 97.4 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 509348 total, 438164 free, 46888 used, 24296 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 450196 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
798 root -91 0 37740 35656 3676 S 9.3 7.0 0:04.47 myprog
797 root -31 0 37740 35656 3676 S 8.4 7.0 0:04.43 myprog
241 root -51 0 0 0 0 R 4.7 0.0 3:55.11 irq/26-2014+
242 root rt 0 0 0 0 S 3.1 0.0 2:33.62 spi3
796 root -21 0 37740 35656 3676 S 1.9 7.0 0:01.14 myprog
794 root 20 0 2848 1892 1536 R 1.0 0.4 0:01.04 top
795 root -11 0 37740 35656 3676 S 0.3 7.0 0:00.37 myprog
3 root 20 0 0 0 0 S 0.2 0.0 0:09.14 ksoftirqd/0
10 root 20 0 0 0 0 S 0.2 0.0 0:00.14 rcuc/0
545 root -51 0 0 0 0 S 0.2 0.0 0:03.74 irq/36-can0
595 root 20 0 1700 880 824 S 0.2 0.2 0:00.99 rngd
1 root 20 0 1712 1168 1104 S 0.0 0.2 0:01.34 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.01 kthreadd
4 root -2 0 0 0 0 S 0.0 0.0 0:07.99 ktimersoftd+
5 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0
6 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H
每个线程的使用情况似乎是正确的,但总数与每个 CPU 的使用情况不匹配。
这不是 top 本身的问题,因为它htop
表现出相同的行为。使用 /proc/stat 中的值进行读取和计算也会产生与 top 和 htop 显示的相同结果。
使用clock_nanosleep() 每 500 微秒调度一次最高优先级线程 ( PID 798
)。尝试每 10 毫秒调度一次线程会显着降低总体 CPU 使用率,但数字仍然不匹配并表现出相同的行为 - 这表明问题不是由当前配置的周期时间低引起的。
在没有实时补丁的库存分发内核上运行我的应用程序会产生类似的结果 - 也表明问题不在于实时补丁。
尝试在单核 CPU 上运行应用程序再次给出类似的结果,表明问题不是由运行多核设置引起的。
- 以前有人经历过类似的事情吗?
- 有人知道为什么每个线程 CPU 使用率的总和与总数不匹配吗?
- 如何获得总 CPU 使用率的可靠值?
提前致谢!
编辑
经过内部进一步讨论该问题后,我们怀疑这可能是采样不足的问题。
如果我们假设内核定期对 CPU 状态(用户空间、内核空间或空闲)进行采样,那么如果采样越多并且线程的调度频率越低,结果就越准确。
进一步假设样本是在计时器滴答中获取的,我将内核的 CONFIG_HZ 从 100Hz 增加到 1000Hz,并修改了我的应用程序,以便每 100 毫秒调度一次线程。为了实现约 50% 的平均负载,进入增加计数器变量的循环会浪费一些 CPU 时间。之后,我不断减少线程的调度间隔,同时调整延迟循环以将平均负载保持在大约 50%。
我的测试得出以下结论:当线程调度在 50ms 和 100ms 时,top 报告的值似乎是正确的。
将调度间隔设置为 10 毫秒,开始显示 2-4% 的差异。进一步将间隔缩短至 5 毫秒,差异将增加至 12%。最后,将间隔进一步减少到 2ms 会完全扰乱 top 输出,导致 top 显示 100% 的空闲时间,而应用程序却使用了 33% 的 CPU 时间。
这似乎证实了我们的猜测,即该问题是由采样不足引起的。
谁能证实这一点吗?有谁知道内核如何测量CPU使用率?
答案1
显示的数字是估计,大部分是通过抽样得到的。适合总体概述,但对于精确到小数的微观管理毫无用处。测量“CPU 使用率”基本上是无用的,您可以通过使系统超载来获得接近 100% 的值(并且几乎没有完成任何工作)。根据工作负载的性能定义总体目标,并根据需要进行测量和调整。
请注意,通过增加 CONFIG_HZ 会增加内核开销(但可能会获得更好的交互响应)。默认值是“典型”工作负载的合理折衷。如果您有确凿的证据表明另一个值更适合您的用例,请更改它们。