![跟踪/监控一个 CPU 上的短期 CPU 密集型进程](https://linux22.com/image/86455/%E8%B7%9F%E8%B8%AA%2F%E7%9B%91%E6%8E%A7%E4%B8%80%E4%B8%AA%20CPU%20%E4%B8%8A%E7%9A%84%E7%9F%AD%E6%9C%9F%20CPU%20%E5%AF%86%E9%9B%86%E5%9E%8B%E8%BF%9B%E7%A8%8B.png)
所以我已经处理这个问题有一段时间了,但我很难找到解决这个问题的工具,我必须想象这个问题的存在。这是我的问题的基础知识:
- 我们运行带有 preempt-rt 补丁的 4 核 RHEL5/centos5,并尝试做一些事情来保证少数应用程序获得合理的确定性(fifo 调度、高优先级等)。不管怎样,我们最近开始运行 PTPv2 客户端,其优先级略高于默认值。事实证明,如果您让 PTPv2 客户端缺乏 CPU 时间,实际上可能会导致一些非常可怕的副作用。无需深入了解细节,事实证明,我们非常确定有什么东西在相对较短的时间内占用了我们将 PTP 守护程序绑定到的 CPU(因为我们的传统日志记录无法捕获它)。所以简短的版本是,我们在用户态启动这个 PTP 客户端(使用调用
daemon
),将其绑定到特定的 CPUtaskset
,然后释放它。每隔几个小时左右一次,某物将抢占我们的 PTP 客户端,或者出于某种原因阻止其运行,持续时间约为 10ms-500ms。
由于我知道 PTP 正在运行的 CPU 上,因此我认为跟踪该 CPU 的运行情况相对容易。不幸的是,事实证明,虽然很容易跟踪某个 CPU 的运行情况在给定的时间(top 和朋友),或最近某个时间的汇总(sar 和朋友),但是令人惊讶的是很难捕获可能只持续很短时间(在毫秒范围内)但不经常(每个)的性能峰值。几个小时左右)。我已经尝试了以下方法(但我并不声称已正确使用它们!因此,如果您认为我错误地使用了正确的工具,请告诉我):
htop/top:top 和朋友们对我了解正在发生的事情非常有用现在。在多核系统上,这变得稍微困难一些,因为现在您必须查看告诉您进程最后在哪个 CPU 上执行的选项,并忽略其余部分,但如果不久前发生了某些事情,并且/或者只是在很短的一段时间内,似乎很难做到我想做的事,除非做一个很多顶级日志记录,非常经常。 Htop 虽然更令人赏心悦目,但似乎提供了或多或少相同的功能,至少对于我想要做的事情来说是这样。
sar:sar 似乎更适合,因为它可以跟踪一段时间内的活动。不过sar好像很会告诉你如何系统在 5、10、15 分钟前正在执行,但没有为什么它就是这样表现的。换句话说,很难弄清楚哪个进程(如果它甚至是用户“进程”)导致了我的问题。不管怎样,我正在研究日志记录和解析地段手工数据。
mpstat:mpstat 非常好,因为您可以轻松地将您要查看的内容限制为您感兴趣的 CPU。然而,它给你的信息是相当不透明的,甚至如果我将 mpstat 设置为基本上持续运行(以捕获相对较快的事件),甚至如果我经理看到活动激增,但没有太多方法可以判断它来自哪里(除非我错过了一些东西,在这种情况下,这就是我在这里的原因!)。
那么,您将如何解决这个问题呢?我知道我的用户层 PTP 守护进程搞砸了,因为在基本层面上,据我了解,它从网络获取绝对时间,而 PTP 试图扭曲时钟频率并滴答以接近该时间。然而,如果由于某种原因(比如 PTP 饥饿/一段时间没有运行),并且它的当前时间和它认为的主时间之间的差异非常大(通常 > 1 秒),它就会继续提前并设置/强制时钟而不扭曲它,这确实让那些不希望时钟发生巨大变化的应用程序陷入困境(在这种情况下,变化超过〜200ms,但当时钟立即变化时,我们确实看到事情崩溃了半秒或更多)...这正是我所看到的。正如我所说,我们将其任务设置为 CPU,因此我知道它在哪个 CPU 上运行。我们在 grub.conf 中 isolcpus,并且还更改了 init 的亲和力,以便 init 生成的子进程在特定(不同)CPU 中生成,因此理论上我们可以完全控制 PTP 运行的 CPU...但是有些东西仍然阻止 PTP 在应该的时候拾取数据包,而我一直在绞尽脑汁地试图追踪它。
作为记录,是的,我确实知道我们大概应该将 PTP 作为内核模块运行,并且我已经能够通过将 PTP 守护进程以高(低)优先级 chrt'ing 到 FIFO 来避免此问题,这似乎确实解决了问题,但这更多的是关于随着时间的推移跟踪特定 CPU 上的系统性能的一般问题。你们会如何解决这样的问题?
多谢!非常感谢任何帮助。
答案1
我遇到了与您类似的问题(Nagios 使用了一个短暂的、自行编写的监控应用程序)。我想出的解决方案收集和 bash while 循环的组合。
因为collectl可以被这样的进程名称唤醒
collectl -sZ -i.1:.1 --procfilt f[your process name]
并且我确信我知道我将调用哪个进程,因此我将其放入这样的循环中:
for((i=1;i<10000;i++)); do nohup /path/to/your/app & done
不确定这是否符合您的需求。另外,最好在任何虚拟机/备用机器上进行测试。
答案2
prelic - 你比我先一步。看到别人回答问题总是很高兴。作为记录,您可以说 -i:.1 ,它将使用默认值 1 秒来处理非进程数据,但由于您没有任何数据,因此输入量会少一些;)
还要非常明确的是,进程名称有点麻烦。对于 f,您需要记录在 /proc/pid/stat 中的名称,这通常有效。如果您使用 c,它将匹配 /proc/pid/cmdline 中包含命令甚至开关路径的任何内容。我的经验法则是,如果使用 f 找不到它,请尝试使用 c。我猜您也熟悉 p、P 和其他选项?我永远无法记住它们,所以总是参考collectl --showsubopt来查看它们。
-标记