代码执行因标头包含而减慢

时间:2012-10-03 13:26:02

标签: c++ linker profiling compiler-optimization

我们这里有一个非常大的程序,它混合了C ++和FORTRAN(对不起)。我的一次签到导致整个应用程序急剧减速(即两倍或更多) - 即使代码区域不受我的更改影响。

事实:

  1. 几乎每个模块都放慢了相似的数量 - 即使是那些不使用我的代码的模块。

  2. 可执行文件大约增加6%。

  3. 在签到之间未更改元数据。

  4. IDE /编译器处于发布模式的VS2010。

  5. 有些.lib文件的大小增加了一倍或三倍。

  6. 我查看了其中一个大小增加了三倍的.lib文件,只有两处变化:

    a)我已经包含了一个大型的头文件,而该文件又包含许多其他文件 - 其中一些包含中等复杂的内联代码。 “附加包含目录”已经从非一个或一个变为大约7个,因为每个头文件#includes包含一个或多个其他目录。

    b)我从这个头文件中调用了4个函数,但这些函数在运行速度减慢期间没有被调用(即它们的执行不能减慢代码速度,但是它们的< em>包含可能是可能的)。

    尽管在论坛中搜索包含头文件是否会减慢执行(而不是编译),但我找不到一篇相关文章。我的问题是:

    任何形式的标头(声明或内联)的#inclusion是否会减慢代码执行

    ?包含内联代码w.r.t是否存在定性或定量差异。执行速度(我知道'内联'只是对编译器的建议)?

    ? .lib大小,.exe大小和执行速度之间的相关性是什么(我期待这里有很多不同且相互矛盾的相关性)?

    ?重构一些头文件,以便他们不需要包含其他文件(通过将这些包含放入.cpp文件,从而减少我的'其他包含目录')改善我的情况,你认为?

    我想最后一个问题是问题的关键,因为它需要付出很多努力......

6 个答案:

答案 0 :(得分:5)

  

任何形式的标头(声明或内联)的#inclusion是否会减慢代码执行速度?

添加未使用的声明或添加未使用的内联定义不会减慢执行速度。然而,我可以想象一些可以减缓执行速度的事情:

  • 某些#define会阻止常用函数的优化内联或宏变体由另一个标题提供。
  • 可能来自标准库中的常用操作的过载,其效率低于默认值。
  

包含内联代码w.r.t是否存在定性或定量差异。执行速度(我知道'inline'只是对编译器的建议)?

好吧,如果代码不可用,则无法内联。如果是,那就可以。通常编译器可以估计内联将保存多少内存,如果它没有帮助则不内联,但偶尔会猜错。在这种情况下,结果将与通常略有帮助的情况大不相同。

  

.lib大小,.exe大小和执行速度之间有什么相关性(我在这里期待很多不同且相互矛盾的相关性)?

完全不同的个案。内联使代码大小膨胀,但可以在每个调用站点上节省大量工作。但是更大的代码会占用更多的缓存,这会减慢它的速度。

  

重构一些头文件,以便他们不需要包含其他文件(通过将这些包含放入.cpp文件,从而减少我的'其他包含目录')改善我的情况,你认为?< / p>

可能会也可能不会。取决于实际原因。

我建议你真的应该找到原因。它几乎肯定是由一些特定的代码引起的,而不是包含的代码量。因此,在更改之前返回修订版并逐位添加。首先包括最里面的标题,然后逐个添加使用它们的标题等。当你到达使事情变得更糟的特定标题时,尝试注释掉它的一部分,直到你将其缩小到特定声明或其中几个。

还要考虑一些观察性能下降的功能。如果你缩小范围并且仍然看不出可能出现的问题,那么你就会有其他人可以重现这个问题,所以你可以将它作为新问题使用。

答案 1 :(得分:1)

更改头文件不能改变执行时间,除非您在生成的二进制文件中包含构建DEBUG或其他诊断代码的内容。

那将是我的猜测。给出输出文件大小的变化。

答案 2 :(得分:1)

你在使用COM吗?您的包含文件是否将STA更改为MTA,反之亦然?现在,您的包含文件是否在您拥有动态链接(lib pragma)之前的库中?包含不再插入lib并且您的代码不再动态链接吗?我重复史蒂夫,是否包含调试库?

DUMPBIN可能会为您提供有关实际构建内容的更多信息。将结果与旧版本进行比较,看看是否有任何重大内容。

其他编辑: 检查测试计算机上的内存使用情况,检查分页活动,以及更大的exe超过阈值的可能性。

答案 3 :(得分:1)

一次失明:

这可能是缓存问题。内联函数并向库中添加“死”代码将导致代码更大,并且可能会在程序执行期间增加缓存未命中量。

您可以通过在执行流程期间监控缓存未命中数来查看这是否是正确的路径。


关于你的评论:

6%多少钱?

如果你的L1缓存溢出(据我所知,即使在现代处理器上它的大小也只有32K左右),你可以交换L1访问进行L2访问,这些访问速度要慢约2倍。 如果溢出L2缓存(范围从256K到2M)并开始访问L3,则在获取页面时会有另外5倍的减速(您可以检查this question,这会给出核心i7的数据)。

以下是wikipedia上缓存未命中的一般说明。

再次,看看这是否真的是问题,你应该监控你的进程在执行过程中遇到的缓存缺失次数(我想process explorer如果你使用的是Windows perf就会显示这个问题,或{{3如果您使用的是Linux)

答案 4 :(得分:0)

  • #inclusion任何形式的标头(声明或内联)是否会减慢代码执行速度? 好吧,如果你的应用必须

    这只会改变代码出现的地方,所以我相信它不会改变任何东西。 (如果你只是将一个函数移动三行,你的代码不会变得更快/更慢吗?)

  • 包含内联代码w.r.t是否存在定性或定量差异。执行速度(我知道'内联'只是对编译器的建议)

    也许。如果你比较内联函数和非内联函数,内联函数可能会更快,因为它的代码只会在适当的位置进行复制,而正常的代码会在函数调用上浪费一些时间。

  • .lib大小,.exe大小和执行速度之间有什么相关性(我期待这里有很多不同且相互矛盾的相关性)

    虽然我可以想象一个假设情况,即较大的文件会降低速度,但我可能会说大部分时间没有相关性。

您的可执行文件可能更大,因为您可能已经覆盖了一些影响执行的宏(比如取消定义一个旨在排除某些代码的定义)。这也可能导致性能下降(即您不希望执行某些代码,但由于意外的宏重新定义,它确实执行了。)

答案 5 :(得分:0)

猜测工作不太可能发现问题。诊断会找到它。 如果减速是两倍,这意味着较慢的代码花费50%的时间做一些不必要的事情。 这很容易找到。

This是我使用的方法,因为它确实找到了问题。 Here's一个例子,here's一堆原因。

我建议您首先在 un 优化代码中诊断问题。 然后当你清除问题时,打开优化器并让它做它的事情。 机会非常好,代码包含您可以修复的重大问题,而优化程序则无法解决。 无论优化器做什么,它都不会让你更容易找到问题而只能修复。