use*_*784 7 c++ compiler-construction optimization performance compiler-optimization
void foo(const int constant)
{
for(int i = 0; i < 1000000; i++) {
// do stuff
if(constant < 10) { // Condition is tested million times :(
// inner loop stuff
}
}
}
Run Code Online (Sandbox Code Playgroud)
对于外循环的每次执行,都检查"常量"的值.但是,常量永远不会改变,所以浪费了大量的CPU时间来测试条件常数<10?一遍又一遍地.人类会在前几次传球后意识到常数永远不变,并且智能地避免一遍又一遍地检查它.编译器是否注意到这一点并对其进行智能优化,或者重复if循环是否不可避免?
就个人而言,我认为这个问题是不可避免的.即使编译器在外部循环之前进行比较并设置某种布尔变量"skip_inner_stuff",仍然必须为外部for循环的每次传递检查此变量.
你对此事有何看法?有没有更有效的方法来编写上述代码段,以避免这个问题?
您描述的优化也称为循环非切换.多年来它一直是优化编译器的标准部分 - 但是如果你想确保你的编译器执行它,请编译你的示例代码并使用一些优化级别(例如gcc中的-O2)并检查生成的代码.
但是,如果编译器无法证明一段代码在整个循环中是不变的 - 例如调用在编译时不可用的外部函数 - 那么实际上,手动将代码提升到循环外部可以净化非常大的性能提升.
一个好的编译器会优化它(当启用优化时)。
如果使用GCC你可以
优化编译并生成汇编代码
gcc -Wall -O2 -fverbose-asm -S source.c
Run Code Online (Sandbox Code Playgroud)
然后查看(使用某些编辑器或类似的寻呼机less)生成的汇编代码source.s
要求 GCC 转储大量(数百个!)中间文件并查看其中的中间 gimple 表示
gcc -Wall -O2 -fdump-tree-all -c source.c
Run Code Online (Sandbox Code Playgroud)
-Wall养成始终使用from gcc(或if 编译 C++ 代码)询问所有警告的习惯g++。
顺便说一句,在实践中,这样的优化(“循环不变代码提升”,如另一个答案所解释的)是必不可少的,因为这种中间代码经常发生,例如在函数内联之后......(想象一下要内联的几个调用foo。 ..)