3

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

事实:

  1. 几乎每个模块都减慢了相似的速度——即使是那些不使用我的代码的模块。

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

  3. 签入之间的元数据未更改。

  4. IDE/编译器是发布模式下的 VS2010。

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

我查看了一个大小增加了两倍的 .lib 文件,但只有两个变化:

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

b) 我从这个头文件中调用了 4 个函数,但是在运行速度变慢的过程中没有调用这些函数(即它们的执行不会减慢代码的速度,但可以想象它们的包含)。

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

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

? 包含内联代码与执行速度是否存在定性或定量差异(我知道“内联”只是对编译器的建议)?

? .lib 大小、.exe 大小和执行速度之间的相关性是什么(我预计这里会有很多不同和矛盾的相关性)?

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

我想最后一个问题是问题的核心,因为这需要付出很多努力......

4

6 回答 6

5

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

添加未使用的声明或添加未使用的内联定义不会减慢执行速度。但是,我可以想象有几件事情会减慢执行速度:

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

包含内联代码与执行速度是否存在定性或定量差异(我知道“内联”只是对编译器的建议)?

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

.lib 大小、.exe 大小和执行速度之间的相关性是什么(我预计这里会有很多不同和矛盾的相关性)?

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

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

它可能会也可能不会。视实际原因而定。

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

还要取出一些您观察到性能下降的功能。如果您缩小范围但仍然看不到可能出现的问题,那么您将拥有一些其他人可以重现该问题的内容,因此您可以将其用作新问题。

于 2012-10-03T13:59:22.783 回答
1

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

那将是我的猜测,尤其是。考虑到输出文件大小的变化。

于 2012-10-03T13:29:34.593 回答
1

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

DUMPBIN 可能会为您提供有关实际构建的内容的更多见解。将结果与旧版本进行比较,看看是否有任何主要的突出之处。

附加编辑:检查测试机器上的内存使用情况,检查分页活动,以防您的较大 exe 越过阈值。

于 2012-10-03T13:42:39.970 回答
1

一次盲拍:

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

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


关于你的评论:

6% 是多少?

如果您的 L1 缓存溢出(据我所知,即使在现代处理器上,它的大小也大约为 32K),您会将 L1 访问换成 L2 访问,这会慢约 2 倍。如果溢出 L2 缓存(范围从 256K 到 2M)并开始访问 L3,则获取页面的速度会再降低 5 倍(您可以查看这个问题,它给出了核心 i7 的数据)。

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

再一次,要查看这是否真的是问题,您应该监控进程在执行期间命中的缓存未命中次数(我认为如果您使用的是 Windows,进程资源管理器会向您显示这一点,或者如果您使用的是 linux ,则为perf )

于 2012-10-03T14:19:52.013 回答
0
  • #inclusion 是否包含任何形式的标头(声明或内联)会减慢代码执行速度?好吧,如果您的应用必须

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

  • 包含内联代码与执行速度是否存在定性或定量差异(我知道“内联”只是对编译器的建议)

    也许。如果比较内联函数和非内联函数,内联函数可能会更快,因为它的代码只会被复制粘贴到适当的位置,而普通函数会在函数调用上浪费一些时间。

  • .lib 大小、.exe 大小和执行速度之间的相关性是什么(我预计这里会有很多不同和矛盾的相关性)

    虽然我可以想象一个较大的文件会减慢速度的假设情况,但我会冒险说大多数时候没有相关性。

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

于 2012-10-03T13:36:28.883 回答
0

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

是我使用的方法,因为它确实找到了问题。 这是一个例子,这里有很多原因。

我建议您首先在未优化的代码中诊断问题。然后,当您清除问题时,打开优化器并让它完成它的工作。很有可能代码包含您可以修复而优化器无法修复的重大问题。不管优化器做什么,它都不会让你更容易找到只有你能解决的问题。

于 2012-10-03T18:08:39.657 回答