How does the first of these two code fragments work 3 times faster than the second when it works more?

Like this code:

var check = 0; for (var numerator = 0; numerator <= maxNumerator; numerator++) { check += numerator >= 0 ? numerator - (int) ((numerator * qdi.Multiplier) >> qdi.Shift) * qdi.Number : numerator - (int) -((-numerator * qdi.Multiplier) >> qdi.Shift) * qdi.Number; } return check; 

runs 3 times faster than this code:

 var check = 0; for (var numerator = 0; numerator <= maxNumerator; numerator++) { check += numerator >= 0 ? (int) ((numerator * qdi.Multiplier) >> qdi.Shift) : (int) -((-numerator * qdi.Multiplier) >> qdi.Shift); } return check; 

The first code fragment performs exactly the same fast division operation (this is multiplication, then right shift), but also subtraction and multiplication, but the JIT compiler seems to produce slower code.

I have a disassembly code for every one available. The slower code pushes the rbx register and subtracts 10h from rsp at the beginning, then adds it back and gives rbx at the end, while faster codes do not.
The slower code also uses the r11 register for most things, where the faster code uses rdx.

Any ideas?

+6
source share
2 answers

It seems that the condition used in the ternary operation can affect the generated code.

It also appears that the triple option may generate less efficient code than a simple if / else.

So, changing the loop code in the second snippest to:

 if (numerator >= 0) check += (int) ((numerator * qdi.Multiplier) >> qdi.Shift); else check += (int) -((-numerator * qdi.Multiplier) >> qdi.Shift); 

or

 if (numerator < 0) check += (int) -((-numerator * qdi.Multiplier) >> qdi.Shift); else check += (int) ((numerator * qdi.Multiplier) >> qdi.Shift); 

or:

 check += numerator < 0 ? (int) -((-numerator * qdi.Multiplier) >> qdi.Shift) : (int) ((numerator * qdi.Multiplier) >> qdi.Shift); 

will create faster working code.

Actually, I find it a little worrying that three of the four combinations produce fast code, and the other can produce slow code ... sometimes.

+1
source

How do you measure? Your description of the assembly language is not like what could lead to a huge difference in performance.

In any case, if it is really much slower, I doubt that someone from the JIT team can say exactly why this is happening. I noticed that when executing .NET microbusiness, which seemingly trivial code changes can lead to the fact that the code will run much faster or slower. If you can make this code (which causes slowness) as simple as possible, you can complain to MS about it in Microsoft Connect.

You can try copying qdi.Multiplier, qdi.Shift and qdi.Number (whatever they are) to local variables, which sometimes helps.

0
source

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


All Articles