2

我有一个更大的 C++ 程序,它首先将数千个小文本文件读入内存并将数据存储在 stl 容器中。这大约需要一分钟。定期地,编译会表现出程序的初始部分将以大约 22-23% 的 CPU 负载运行的行为。一旦该步骤结束,它会回到 ~100% CPU。O2 标志打开但不一致时更有可能发生这种情况。使用 -p 标志的情况更少发生,这使得几乎不可能进行分析。我确实捕获了一次,但 gprof 输出没有帮助 - 一切都以相同的相对速度运行,只是在 cpu 使用率低的情况下。

我很确定这与多核无关。我确实有一个四核 cpu,并且大部分代码都是多线程的,但我在运行单线程时测试了这个问题。此外,当我在多个线程中运行有问题的步骤时,每个线程仅以约 20% 的 CPU 运行。

对于这个问题的含糊之处,我提前道歉,但我已经没有关于如何进一步解决它的想法,所以任何提示都可能会有所帮助。

更新:为了确保清楚,代码的有问题的部分有时(大约 30-40% 的编译)运行在 100% 的 CPU 上,所以很难相信 I/O 是瓶颈

4

3 回答 3

4

这是缓冲区缓存


我的猜测是,您看到的是Linux 缓冲区高速缓存运行的结果。

这数千个文件将需要很长时间才能从磁盘读取,并且 CPU 将主要等待旋转和寻道延迟。报告的 CPU 时间使用率将较低,以百分比表示。(但总体上可能更大。)

但是一旦读取,这些小文件就会完全缓存在内存中,并且访问每个文件(在后续运行中)成为纯粹的 CPU 绑定活动。

块是否保留在缓存中取决于干预活动,例如重新编译。当新程序运行并读取其他文件时,程序和文件将被缓存,旧块将被丢弃,显然,内存密集型工作负载也会清除缓冲区缓存。

于 2012-12-12T23:01:33.617 回答
3

由于您正在读取大量小文件,因此您的程序大部分时间都在等待磁盘 I/O 时被阻塞。由于 CPU 在等待磁盘向其发送数据时并不忙,因此您会看到负载明显低于 100%。一旦结束,现在你的 CPU 受限,你的程序将占用所有可用的 CPU 时间。

它有时工作得更快的事实是因为(正如 Jarryd 和 DigitalRoss 所提到的)一旦你将它们读入系统内存,它们就在操作系统的缓存中,所以后续的加载速度会快一个数量级,除非它们已经被其他磁盘 I/O 驱逐。因此,如果您背靠背运行程序,第二次运行可能会快得多。如果您等待一段时间(同时做其他事情),可能已经有足够的其他磁盘 I/O 将这些文件从缓存中逐出,在这种情况下,再次读取它们需要很长时间。

于 2012-12-12T22:58:43.927 回答
3

除了提到缓冲区缓存的其他答案之外,如果您想了解编译过程中发生了什么,您可以将以下一些标志传递给 GCC(即到g++,可能作为CXXFLAGS您的设置Makefile):

  • -v要求g++显示涉及的子进程(例如cc1plus,对于正确的 C++ 编译器)
  • -time要求g++报告每个子流程的时间
  • -ftime-report要求g++(实际上cc1plus)报告编译器内部阶段或传递的时间。
于 2012-12-13T06:24:13.073 回答