I doubt repeatedly adding floating point numbers is a good idea. With every addition the sum increases further away from the addend, and with their growing relative difference problems grow as well. Just because the algebra works it doesn't guarantee that the code does, too.
Why does this code execute more slowly after strength-reducing multiplications?
71–80 of 155 posts
Re: Why does this code execute more slowly after strength-reducing multiplications?
#72Re: Why does this code execute more slowly after strength-reducing multiplications?
#73If we ignore the details, then this is a perfect example of how simpler code should be preferred _by default_ over complex code. Both for performance and reasoning. In this case and often elsewhere, these are related things. I'm taking the definition of simple and complex (or complected) from this talk[0]. In short: Simple means individual pieces are standing on their own, not necessarily easy or minimal. Complex mea…
You can't ignore the details if you want the fastest performance. Unfortunately sometimes the solution that's the fastest is also more complex. Simplicity tends to win and also is less likely to be buggy, easier to maintain etc but sometimes the fastest code deliberately introduces coupling, hardware specific cache shenanigans or unreadable hand written asm and/or inlined SIMD. This is often counter to your hypothesi…
>> this is a perfect example of how simpler code should be preferred _by default_ over complex code.
Extra emphasis on *by default*.
You are both on the same side of the coin. This is the essence of "premature optimization is the root of all evil". Simplicity should be the default. Once you know your implementation is solid, then you can go back and optimize.
TFA is quite contrived, but imagine a much more complex process. You see some code:
for i in loop:
foo[i] = myfunc(foo[i], bar[i])
You have to go in and dig into why exactly foo is being fed back in at every step. But if instead you saw: for i in loop:
foo[i] = myfunc(bar[i])
You immediately know you have more options at your disposal to optimize that loop. Further, the compiler immediately knows it has more options. Maybe this is a good option for automatic unrolling or Duff's device. Maybe you wanna send this to a gpu shader, or use a macro to parallelize the loop. But it's a lot harder to get to that point if your starting point is the complected, stateful one.Re: Why does this code execute more slowly after strength-reducing multiplications?
#74Tldr: autovectorizer transforms the first code into SIMD instructions, but the second into 64 bit instructions. SIMD is very powerful, and modern compilers can sometimes simd-ify your code automatically. ------- The second code can probably become SIMD as well, but it's beyond GCC's ability to autovectorizer it in that form. I kinda want to give it a go myself but don't have time today... Autovectorizers are mysterio…
> Tldr: autovectorizer transforms the first code into SIMD instructions, but the second into 64 bit instructions. That's not the tldr. It's actually more wrong than right. The actual TLDR is: loop dependencies prohibit the compiler _and_ your CPU from parallelizing. The SIMD part is the compiler, the more important part here is the CPU though. Long explanation: Let's start with the compiler. Yes, the first version ca…
Re: Why does this code execute more slowly after strength-reducing multiplications?
#75Re: Why does this code execute more slowly after strength-reducing multiplications?
#76The suggested "slower" optimisation does fundamentally use less instructions. Chucking more hardware at parallelisable problems makes it run faster but does not necessarily reduce the power requirements much because there are fundamentally the same number of instructions, it's just gobbling up the same power over a shorter period of time - The "slower" serial algorithm uses less instructions and in theory less power in total. Disclaimer: I mean power vs speed fundamentally in theory, in practice there may be no measurable difference depending on the particular CPU and code.
Re: Why does this code execute more slowly after strength-reducing multiplications?
#77Vectorisation is not free, There is one other dimension to optimise for: power. The suggested "slower" optimisation does fundamentally use less instructions. Chucking more hardware at parallelisable problems makes it run faster but does not necessarily reduce the power requirements much because there are fundamentally the same number of instructions, it's just gobbling up the same power over a shorter period of time…
While it might sound intuitive that SIMD instructions consume more power, I don't think that's necessarily true to a relevant degree in practice. My understanding is CPU power consumption is mostly tied to inefficiences that cause energy loss via heat, while the actual computation doesn't consume any energy per se. So electrons traveling a more complex path probably cause somehwat more energy loss as there is more wire/transistors to pass. But most of the total loss doesn't actually occure in the ALU. Empirically from what you can see operating systems do, the most effective way of consuming less power is actually running on a slower clock cycle and the most effective way to achieve that is getting work done faster and that's not tied to the number of instructions.
The Stackoverflow question here [1] seems to suggest that SIMD vs no SIMD has a neglectable overhead compared to entering a lower power state sooner.
[1] https://stackoverflow.com/questions/19722950/do-sse-instruct...
Re: Why does this code execute more slowly after strength-reducing multiplications?
#78In the post, multiplications and 2 additions are not faster than 2 additions. The post compares (1) loop code that can be vectorized, as loop rounds are independent and do not depend on the result from the previous round, and (2) an "optimization" that makes calculations shorter, but also makes each loop round depend on the result of the previous round, so this cannot be vectorized.
More generally, “stop storing state, unless it makes the program less complicated.” The first version is simple. The second version is more complicated. The simplicity is because the first version can be represented as a formula; imagine trying to write out the second version as a formula, and the complexity becomes obvious. (The addition loop would have to be written as a recurrence relation, which of course means e…
I had hoped that functional programming languages would lead us to automatic high-level parallelization. That hasn't happened much in the real world. But what we got is "write code like a functional programmer would even in a low-level language and the compiler and the ISA will parallelize it for you." That surprises me, but I'll take it.
Re: Why does this code execute more slowly after strength-reducing multiplications?
#79Earlier quoted context omitted.
Not really, the compiler did the round-trip into the local variable (memory), I did it via register. I asked around at the time and someone mentioned that I might have overtaxed certain execution ports or something like that, but yeah that just cemented my belief that x86 optimization is not my cup of tea anymore. Better to spend time learning how to write code the compiler can optimize well.
The compiler doesn’t know anything about optimizing x86 code either. The actual details there are too secret for Intel to want to accurately describe them in gcc, they’re different across different CPUs, and compilers just aren’t as good as you think they are. (But CPUs are usually better than you think they are.)
I'm wondering how the incentives play out to keep this stuff private?
Re: Why does this code execute more slowly after strength-reducing multiplications?
#80Seems like you can have the cake and eat it too, by manually parallelizing the code to something like this: double A4 = A+A+A+A; double Z = 3A+B; double Y1 = C; double Y2 = A+B+C; int i; // ... setup unroll when LEN is odd... for(i=0; i Probably not entirely functional as written, but you get the idea: unroll the loop so that the data dependent paths can each be done in parallel. For the machine being considered, a 4…