4

我们有一个运行 Linux 2.6.32.20 的基于 ARM9 的嵌入式板。该设备是一个摄像机,其相关的捕获/压缩硬件将数据放入 ARM 内存中的输入 fifo,然后 ARM 从用户空间访问该输入FIFO。我们还有一个用于高级控制的编码器驱动程序。

应用程序级代码中的一个线程检查此用户空间 fifo,并在有数据时通过套接字将其发送出去。为了避免该线程需要轮询用户空间 fifo 以获取数据的开销,我们对驱动程序进行了非常简单的 read() 调用,实际上它只是挂起,直到 fifo 中有任何数据(没有真正“读取”到read() 调用中提供的缓冲区)。然后这个 read() 调用返回,线程继续从 fifo 读取数据,直到它为空,然后通过调用假的 read() 调用再次挂起。

该系统非常有效,通过在检测到丢帧之前可以传输多少网络流来衡量。但是我们已经确定,使用虚假的 read() 调用会导致 Linux“top”实用程序报告我们的应用程序使用大量 CPU。

我们已经构建了 2 个版本的应用程序 - 一个与上面一样运行,另一个相同,只是它从不调用假 read(),而是通过干预 usleep() 调用轮询 fifo。当我们查看“top”报告的 2 种情况下每个发送 5 个流的 CPU 使用率时,我们得到:

1) read() 版本:CPU 12%
2) usleep() 版本:CPU 4%

当然,现实中的轮询效率较低,如果我们忽略“top”所说的内容,而只是在我们看到丢帧之前测量两个版本可以同时传输多少网络流,那么上面的版本 1 获胜。

我们已经验证了上面的 read() 调用运行正常。如果某些错误导致 read() 调用立即返回,即使 fifo 中没有数据,那么线程最终将执行昂贵的连续轮询。但这种情况并非如此; read() 调用使线程每秒准确运行 30 次。

我们认为我们的玩具busybox版本的“top”可能采取了一些捷径——但这些结果并没有出现在top用来计算其显示数字的/proc//stat中的原始数字中。

这个问题一定是Linux内核本身如何收集/proc//stat中显示的数字的一些限制。

如果有人理解为什么会这样,请指出我正确的方向。谢谢!

4

2 回答 2

1

我可以保证 top 没有骗你。如果它说您的进程正在使用 12% 的 CPU,那么它正在使用 12% 的 CPU。没有两种方法。

显然,调用 usleep 不会花费太多时间,因为它会导致进程在(至少)请求的时间内进入睡眠状态。这可能是每次调用睡眠的 100 个周期。Read 做的远不止这些,所以我并不惊讶它需要更多的 CPU 时间来做这件事——尤其是如果你做很多事情的话。

阅读将:

  1. 检查您的句柄是否有效。
  2. 检查您的缓冲区指针和长度是否有效。
  3. 将长度从用户空间复制到内核空间。
  4. 将读取的数据插入到合适的数据结构中。
  5. 查找相关句柄以及向哪个驱动程序发出请求。
  6. 向您的驱动程序发出读取请求。
  7. 驱动程序使进程休眠[假设没有可用数据]。
  8. 驱动程序唤醒进程[当有可用数据时]。
  9. 将读取长度数据复制到用户空间。
  10. 返回给调用者。

将其与睡眠进行比较:

  1. 去睡觉。
  2. 醒来。
  3. 返回给用户。

当然,“去睡觉”不是一个简单的功能,唤醒也不是微不足道的。但它们是相同的操作,并且在睡眠期间,进程不使用 CPU。

您可以通过从 /dev/zero 读取并在两者之间休眠来轻松计算出读取的开销。/dev/zero是一个立即返回的设备,其缓冲区填充为零。

或者,您可以尝试使用类似的东西oprofile进行性能分析,看看时间花在了哪里。

但我很确定你top没有说谎。

于 2013-01-10T21:26:38.767 回答
1

的确,“保证”这个词用在这里太强了。我目前正在使用 3.8 和 3.7 内核对 2 个不同的基于 ARM 的板进行性能测试,并且两者都在顶部报告奇怪的事情。一种是使用公司提供的库存内核,另一种是使用 Arch-Linux。我不相信这些内核以任何方式被“黑客入侵”。硬件似乎并不好。一个是报告每个进程的 CPU 使用率为 0%,即使顶部的总数显示 50% 空闲。另一个显示 dma 驱动程序相关的进程总是使用 100% 的 CPU。所以在我非常有限的经验中,top 一直是我认为的问题。

于 2013-07-15T19:04:35.023 回答