使用多线程应用程序了解多核系统上的平均负载

使用多线程应用程序了解多核系统上的平均负载

我们的系统上的平均负载有一个奇怪的情况。它正在运行一个名为 ZAG 的应用程序,该应用程序一天中大部分时间都处于空闲状态。但每隔 80 分钟左右,就会出现某种持续 5-15 分钟的活动爆发。爆发时,平均负载可以攀升至 60、70、80、100 或更高。有趣的是:在这些高突发期间,我们将看到 htop 中的 CPU 利用率百分比显示每个 CPU 的利用率仅为 10-20%。此外,我编写的脚本显示 CPU 使用率较低;在空闲时间:

ps -eTo psr,user,pid,tid,cputime,class,rtprio,ni,pri,pcpu,stat,wchan:14,args | grep  ZAG | awk '{sum += $10} END{print sum;}'

可能会返回 535.0...也就是说,将 ZAG 应用程序中的所有 CPU 百分比相加会返回 CPU 的 535.0%,或者系统上所有 CPU 的 5.35/32 或 16.7% 利用率。简而言之,没有一个 CPU 的运行率接近 100%,这正是我们在大部分空闲时间内所期望的。

在这次事件中,结果约为 538.0%……只是稍微高了一点。我还在运行队列上看到更多线程,如下所示

while true; do ps -eTo psr,user,pid,tid,cputime,class,rtprio,ni,pri,pcpu,stat,wchan:14,args | grep ZAG | grep ' Rl' | wc -l; sleep 0.5; done

因此,CPU 利用率略有上升,并且有更多线程在运行。但即使平均负载猛增,CPU 的使用量似乎也没有增加。关于磁盘 I/O 或网络 I/O 的情况始终很少发生; SAR 数据显示在此爆发期间没有明显的增加。内存利用率没有增加,系统上大约 1700 个总进程中的进程数量可能会增加几个,但仅此而已。这些时候 cron 中没有发生任何事情。 htop 或 top 输出显示,此时确实发生了一些 CPU 利用率,主要是用户 CPU(top 报告的系统 CPU 少于 5%)。所以看起来没有任何东西在等待数据。

我没有注意到 /proc/interrupts 中有任何异常。重新调度中断似乎很严重,但我抽查了六个核心,包括偶数和奇数 NUMA 节点,它们似乎稳定在每个处理器每秒约 1400 个。

这是一台开启超线程的 16 核机器(E5-2667 v4 处理器)。它有 36 个 ZAG 进程和 729 个 ZAG Therad,分别由 ps -ef 和 ps -eTf 显示。

所以这让我想知道:为什么我的 CPU 利用率如此低,而我的平均负载却如此高?是否是因为在我的 36 个 ZAG 进程中,我有超过 700 个线程,并且可能其中的一个线程sched_yield()仍在运行队列中,但没有积累 CPU?或者sched_yield()不再可运行,但处于不可中断状态(见下文)?

根据布伦丹·格雷格的说法https://www.brendangregg.com/blog/2017-08-08/linux-load-averages.html,“当平均负载首次出现在 Linux 中时,与其他操作系统一样,它们反映了 CPU 需求。但后来 Linux 将其更改为不仅包括可运行任务,还包括处于不可中断状态(TASK_UNINTERRUPTIBLE 或 nr_uninterruptible)的任务。这种状态是由希望避免信号中断的代码路径使用,其中包括磁盘 I/O 上阻塞的任务和一些锁......但是 Linux 平均负载有时不会过高,超出了磁盘 I/O 所能解释的范围。是的,虽然我猜测这是由于 1993 年不存在的使用 TASK_UNINTERRUPTIBLE 的新代码路径所致。在 Linux 0.99.14 中,有 13 个代码路径直接设置 TASK_UNINTERRUPTIBLE 或 TASK_SWAPPING (交换状态后来被删除) Linux)。如今,在 Linux 4.12 中,有近 400 个设置 TASK_UNINTERRUPTIBLE 的代码路径,包括一些锁定原语,这些代码路径之一可能不应该包含在负载平均值中......”

答案1

我想我找到了。

问题很简单:

如何解释高平均负载(即运行队列上有很多内容)和低 CPU 利用率?

我相信答案就在 sched_yield() 系统调用中。如果线程让步给其他线程,它们会保留在 CPU 的运行队列中,但可能不会执行大量操作。

https://books.google.com/books?id=9yIEji1UheIC&pg=PA370&lpg=PA370&dq=sched_yield+reli[…]&hl=en&sa=X&ved=2ahUKEwimrNvwqrL1AhWIhOAKHQLyBDcQ6AF6BAgCE​​AM

如果该链接消失:这是 Bovet 和 Cesati 的“Understanding the Linux Kernel”,第二版第 370 页。

它说,“sched_yield()系统调用允许进程自愿放弃CPU而不被挂起;该进程保持在task_running状态,但调度程序将其放在运行队列列表的末尾。这样,其他进程具有相同动态优先级的进程有机会运行。该调用主要由 sched_fifo 进程使用。”

在这里他们提到了“过程”,但在手册页中https://man7.org/linux/man-pages/man2/sched_yield.2.html描述中说,“sched_yield() 导致调用线程放弃 CPU。该线程因其静态优先级而被移动到队列末尾,然后一个新线程开始运行。”

因此,从概念上讲,我们具有相同的行为:事物到达运行队列列表的末尾。根据我们所看到的情况,线程保持在 task_running 状态是有意义的。

相关内容