Disproportionate processing time with arithmetic operations [C]

Can someone explain what is happening here with this small program?

#include<stdio.h> int main() { float a=0.577; float b=0.921; float c; int i; for (i=0;i<100000000;i+=1){ c=0.7*a-0.2*b; //a=0.145*c+2.7*b; } printf ("%.3f\n",c); } 

Note that the line is commented out.

I compiled it first without a string, and then using a string. (Used by gcc -O2 ... ). And measured the processing time. I was very surprised to learn that the 0.001s time was 0.001s compared to 2.444s . And that doesn't make much sense. Rather, there must be some logic for this.

Can you explain what is happening and how to mitigate this problem?

I am working on a program that processes a huge amount of data, and it seems to me that I faced the same performance problem.

I was considering switching from float to integers, but it seems that with integers it behaves the same.

EDIT: At the end, the solution was trivial and logical. Therefore, I thank you for all the answers and explanations!

+6
source share
5 answers

In the first case, the calculated value was constant. The compiler calculated c = 0.7 * 0.577 - 0.2 * 0.921 at compile time . It is even free to optimize the cycle, since nothing changes in it ( a , b and c are invariant).

In the second case, a and c change for each iteration, so they need to be calculated 100000000 times.

+13
source

Good optimizers are very good.

Since a single-line calculation returns the same value at each iteration, there is no need to recalculate anything in the loop, so the optimizer does not.

When changing a too (with two-line calculation), it should start a loop.

Therefore, the time difference.

+3
source

Without a commented line, the compiler can optimize the entire loop. The set value does not change relative to the cycle.

With a commented line, the value of a changes each time the loop starts, so the loop cannot be optimized.

That is, your program and this:

 int main() { float a=0.577; float b=0.921; float c; int i; c=0.7*a-0.2*b; for (i=0;i<100000000;i+=1){ //a=0.145*c+2.7*b; } printf ("%.3f\n",c); } 

produces the same answer if and only if this line is commented out.

+2
source

Here is the code I get from compiling your example with optimizations enabled:

 (__TEXT,__text) section _main: 0000000100000f20 pushq %rbp 0000000100000f21 movq %rsp, %rbp 0000000100000f24 leaq 61(%rip), %rdi ## literal pool for: %.3f 0000000100000f2b movsd 45(%rip), %xmm0 0000000100000f33 movb $1, %al 0000000100000f35 callq 0x100000f3e ## symbol stub for: _printf 0000000100000f3a xorl %eax, %eax 0000000100000f3c popq %rbp 0000000100000f3d ret 

Note that the loop does not even start - the compiler has completely optimized it, as it can say that the only destination c that matters is the last.

Unlike re-setting the commented line, the loop should execute, and the output code looks like this:

 (__TEXT,__text) section _main: 0000000100000ea0 pushq %rbp 0000000100000ea1 movq %rsp, %rbp 0000000100000ea4 movss 148(%rip), %xmm5 0000000100000eac movl $100000000, %eax 0000000100000eb1 movsd 143(%rip), %xmm1 0000000100000eb9 movsd 143(%rip), %xmm2 0000000100000ec1 movsd 143(%rip), %xmm3 0000000100000ec9 movsd 143(%rip), %xmm4 0000000100000ed1 nopw %cs:(%rax,%rax) 0000000100000ee0 xorps %xmm0, %xmm0 0000000100000ee3 cvtss2sd %xmm5, %xmm0 0000000100000ee7 mulsd %xmm1, %xmm0 0000000100000eeb addsd %xmm2, %xmm0 0000000100000eef cvtsd2ss %xmm0, %xmm0 0000000100000ef3 cvtss2sd %xmm0, %xmm0 0000000100000ef7 movaps %xmm0, %xmm5 0000000100000efa mulsd %xmm3, %xmm5 0000000100000efe addsd %xmm4, %xmm5 0000000100000f02 decl %eax 0000000100000f04 cvtsd2ss %xmm5, %xmm5 0000000100000f08 jne 0x100000ee0 0000000100000f0a leaq 87(%rip), %rdi ## literal pool for: %.3f 0000000100000f11 movb $1, %al 0000000100000f13 callq 0x100000f1c ## symbol stub for: _printf 0000000100000f18 xorl %eax, %eax 0000000100000f1a popq %rbp 0000000100000f1b ret 

Quite another, as you can see.

+2
source

When the string a=0.145*c+2.7*b; commented out, the only expression inside your loop is cyclically invariant. Your optimizer knows this, so he moves the computation out of the loop. Then the optimizer does not notice anything in the loop, so it gets rid of the loop.

When you return the string, the expression is no longer cycloinvariant.

+2
source

Source: https://habr.com/ru/post/950022/


All Articles