编译器优化导致程序运行速度变慢

时间:2022-05-18 19:24:34

I have the following piece of code that I wrote in C. Its fairly simple as it just right bit-shifts x for every loop of for.

我在C中编写了以下代码。它非常简单,因为它恰好为每个for循环移位x。

int main() {
   int x = 1;
   for (int i = 0; i > -2; i++) {
      x >> 2;
   }
}

Now the strange thing that is happening is that when I just compile it without any optimizations or with first level optimization (-O), it runs just fine (I am timing the executable and its about 1.4s with -O and 5.4s without any optimizations.

现在发生的奇怪的事情是,当我只是编译它而没有任何优化或第一级优化(-O)时,它运行得很好(我正在计时可执行文件和它的大约1.4s -O和5.4s没有任何优化。

Now when I add -O2 or -O3 switch for compilation and time the resulting executable, it doesn't stop (I have tested for up to 60s).

现在当我添加-O2或-O3开关进行编译并为生成的可执行文件计时时,它不会停止(我已经测试了多达60秒)。

Any ideas on what might be causing this?

关于可能导致这种情况的任何想法?

3 个解决方案

#1


17  

The optimized loop is producing an infinite loop which is a result of you depending on signed integer overflow. Signed integer overflow is undefined behavior in C and should not be depended on. Not only can it confuse developers it may also be optimized out by the compiler.

优化的循环产生一个无限循环,这是您依赖于有符号整数溢出的结果。有符号整数溢出是C中未定义的行为,不应该依赖它。它不仅会使开发人员感到困惑,而且编译器也可能会对其进行优化。

Assembly (no optimizations): gcc -std=c99 -S -O0 main.c

汇编(无优化):gcc -std = c99 -S -O0 main.c

_main:
LFB2:
    pushq   %rbp
LCFI0:
    movq    %rsp, %rbp
LCFI1:
    movl    $1, -4(%rbp)
    movl    $0, -8(%rbp)
    jmp L2
L3:
    incl    -8(%rbp)
L2:
    cmpl    $-2, -8(%rbp)
    jg  L3
    movl    $0, %eax
    leave
    ret


Assembly (optimized level 3): gcc -std=c99 -S -O3 main.c

装配(优化级别3):gcc -std = c99 -S -O3 main.c

_main:
LFB2:
    pushq   %rbp
LCFI0:
    movq    %rsp, %rbp
LCFI1:
L2:
    jmp L2  #<- infinite loop

#2


7  

You will get the definitive answer by looking at the binary that's produced (using objdump or something).

通过查看生成的二进制文件(使用objdump或其他内容),您将获得明确的答案。

But as others have noted, this is probably because you're relying on undefined behaviour. One possible explanation is that the compiler is free to assume that i will never be less than -2, and so will eliminate the conditional entirely, and convert this into an infinite loop.

但正如其他人所说,这可能是因为你依赖于未定义的行为。一种可能的解释是编译器可以*地假设我永远不会小于-2,因此将完全消除条件,并将其转换为无限循环。

Also, your code has no observable side effects, so the compiler is also free to optimise the entire program away to nothing, if it likes.

此外,您的代码没有可观察到的副作用,因此编译器也可以*地优化整个程序,如果它喜欢的话。

#3


2  

Additional information about why integer overflows are undefined can be found here:

有关为什么整数溢出未定义的其他信息,请访问:

http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html

Search for the paragraph "Signed integer overflow".

搜索“有符号整数溢出”段落。

#1


17  

The optimized loop is producing an infinite loop which is a result of you depending on signed integer overflow. Signed integer overflow is undefined behavior in C and should not be depended on. Not only can it confuse developers it may also be optimized out by the compiler.

优化的循环产生一个无限循环,这是您依赖于有符号整数溢出的结果。有符号整数溢出是C中未定义的行为,不应该依赖它。它不仅会使开发人员感到困惑,而且编译器也可能会对其进行优化。

Assembly (no optimizations): gcc -std=c99 -S -O0 main.c

汇编(无优化):gcc -std = c99 -S -O0 main.c

_main:
LFB2:
    pushq   %rbp
LCFI0:
    movq    %rsp, %rbp
LCFI1:
    movl    $1, -4(%rbp)
    movl    $0, -8(%rbp)
    jmp L2
L3:
    incl    -8(%rbp)
L2:
    cmpl    $-2, -8(%rbp)
    jg  L3
    movl    $0, %eax
    leave
    ret


Assembly (optimized level 3): gcc -std=c99 -S -O3 main.c

装配(优化级别3):gcc -std = c99 -S -O3 main.c

_main:
LFB2:
    pushq   %rbp
LCFI0:
    movq    %rsp, %rbp
LCFI1:
L2:
    jmp L2  #<- infinite loop

#2


7  

You will get the definitive answer by looking at the binary that's produced (using objdump or something).

通过查看生成的二进制文件(使用objdump或其他内容),您将获得明确的答案。

But as others have noted, this is probably because you're relying on undefined behaviour. One possible explanation is that the compiler is free to assume that i will never be less than -2, and so will eliminate the conditional entirely, and convert this into an infinite loop.

但正如其他人所说,这可能是因为你依赖于未定义的行为。一种可能的解释是编译器可以*地假设我永远不会小于-2,因此将完全消除条件,并将其转换为无限循环。

Also, your code has no observable side effects, so the compiler is also free to optimise the entire program away to nothing, if it likes.

此外,您的代码没有可观察到的副作用,因此编译器也可以*地优化整个程序,如果它喜欢的话。

#3


2  

Additional information about why integer overflows are undefined can be found here:

有关为什么整数溢出未定义的其他信息,请访问:

http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html

Search for the paragraph "Signed integer overflow".

搜索“有符号整数溢出”段落。