Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/151.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 最好不要相信gcc默认内联线?_C++_C_Gcc_Optimization_Inline - Fatal编程技术网

C++ 最好不要相信gcc默认内联线?

C++ 最好不要相信gcc默认内联线?,c++,c,gcc,optimization,inline,C++,C,Gcc,Optimization,Inline,我做了一些手工优化我的一些代码,不知怎么被gcc咬了 运行测试时,原始代码大约需要3.5秒才能完成执行 我很困惑为什么我的优化版本现在需要大约4.3秒来完成测试 我将\uuuuu属性(总是内联的)应用于探查器中的一个本地静态函数,现在它可以在2.9秒内运行。很好 我一直相信gcc会在函数内联中做出决定,但显然它看起来并不那么完美。我不明白为什么gcc最终做出了一个非常错误的决定:是否将文件范围静态函数与-O3-flto-fwhole程序内联。编译器真的只是对内联函数的成本效益做了一个客套估计吗?

我做了一些手工优化我的一些代码,不知怎么被gcc咬了

运行测试时,原始代码大约需要3.5秒才能完成执行

我很困惑为什么我的优化版本现在需要大约4.3秒来完成测试

我将
\uuuuu属性(总是内联的)
应用于探查器中的一个本地静态函数,现在它可以在2.9秒内运行。很好


我一直相信gcc会在函数内联中做出决定,但显然它看起来并不那么完美。我不明白为什么gcc最终做出了一个非常错误的决定:是否将文件范围静态函数与
-O3-flto-fwhole程序
内联。编译器真的只是对内联函数的成本效益做了一个客套估计吗?

编辑:回答实际问题,是的,编译器确实进行了“猜测”-或者正如技术术语所说,它使用“启发式”-来确定内联特定函数将导致的速度与空间的增益。启发式被定义为“一种实用但理论上并不完美的解决方案”。结束编辑

如果看不到代码,很难说出编译器中发生了什么。您正在做正确的事情来评测代码,请尝试手动优化并再次评测-如果更好,请保留它

编译器经常出错,这并不罕见。人类有时更聪明,但我通常相信编译器会把它做对。这可能是因为函数被多次调用,而且相当大,因此编译器决定“它高于代码膨胀与速度增益的阈值”?或者它可能只是没有得到“内联有多好/有多差”的正确计算

请记住,编译器是泛型的,适用于一种情况的东西可能会使另一种情况变得更糟-因此编译器必须妥协并提出一些合理的启发式方法,这些方法不会经常给出太坏的结果

如果您可以运行概要文件引导的优化,它可能会帮助编译器做出正确的决策(因为它将知道有多少次迭代以及执行特定分支的频率)

如果您可以与GCC编译器团队共享代码,请将其报告为错误-他们可能会因为“太特殊”或诸如此类的原因而忽略/拒绝该代码,但很可能这个特殊情况是“遗漏了”的


我认为可以公平地说,编译器“经常正确地进行编译”,但这并不意味着它总是正确地进行编译。我最近查看了一些从Clang生成的代码,它需要一大堆额外的指令来展开循环-但在最典型的情况下,循环将是一次迭代,并且不会超过16次。因此,将循环展开因子为4的附加指令对于一个循环来说是完全浪费的,甚至对于可能最长的循环来说也是毫无用处的。自然循环“滚动”大约只有3-4条指令,因此即使循环大得多,节省的指令也相当少——但当然,如果是一百万次迭代,它可能会将该函数的速度提高三倍。

当然,它使用的是启发式。决定什么是完美的行动通常是不可能的,就像解决停顿问题一样。正确的操作也可能取决于你的应用程序接收到什么样的输入,编译器对此一无所知。。。也许配置文件引导优化可以做得更好,但是gcc是否做得那么聪明,我不知道……如果您还没有这样做,您还可以设置CPU架构,例如使用标志
-march=native
。这可以实现更多优化,例如可能的矢量化。GCC还有一个并行STL实现,它带来了巨大的性能优势。此外,对于性能关键代码,我会考虑使用英特尔ICC。因此,您发现了一个编译器没有做正确的事情的情况。想打赌你需要多少年才能找到下一个吗?@KarolyHorvath:使用
-fprofile generate
/
-fprofile Use
为编译器提供决定内联哪些函数和展开哪些循环所需的数据。它还布置了分支,这样公共路径的执行分支就更少了,从而减少了分支预测器的压力,也减少了指令获取流中的气泡。@PeterCordes:我的意思是我知道你可以这样做,但我不确定它是否能解决这个特定问题。我很想听听OP的反馈。编辑标签之外的东西实际上更有用@xiver77:是的,只是有时候我得到的回答是“你没有回答真正的问题”,所以我想我也会回答这个问题;)使用
-fprofile generate
/
-fprofile use
几乎可以避免您描述的所有问题(尤其是无用的展开)。(gcc过去在
-O3
中包括
-funroll循环
,就像clang现在一样。现在,gcc只使用
-fprofile use
启用
-funroll循环
(当然,如果您直接使用该选项的话)。)