关于c ++:gcc编译(有时)导致cpu欠载

gcc compilations (sometimes) result in cpu underload

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

我很确定这与多核无关。我有一个四核CPU,大部分代码是多线程的,但是我在运行一个线程时测试了这个问题。另外,当我在多个线程中运行有问题的步骤时,每个线程只在大约20%的CPU下运行。

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

更新:为了确保清楚,代码中有问题的部分有时(约30-40%的编译)以100%的CPU运行,因此很难相信(否则是合理的)I/O是瓶颈的论点


是缓存

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

这数千个文件需要很长时间才能从磁盘中读取,CPU将主要等待轮转和查找延迟。报告的CPU使用时间将很低,以百分比表示。(但总的来说可能更大。)

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

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


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

  • EDCOX1〔3〕要求EDCOX1〔0〕以显示所涉及的子过程(例如,对于适当的C++编译器,EDCOX1=5)
  • -time要求g++上报各子流程时间
  • -ftime-report要求g++(实际上是cc1plus报告编译程序内部阶段或过程的时间。


由于您正在读取大量的小文件,因此大多数情况下,您的程序都会被阻止等待磁盘I/O。由于CPU在等待磁盘将数据传送到它时并不忙,因此您看到的负载明显小于100%。一旦这一切结束,现在你的CPU绑定,你的程序将消耗所有可用的CPU时间。

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