Live data from Hacker News

Replacing 32-bit loop variable with 64-bit introduces performance deviations

stackoverflow.com

1–10 of 26 posts

Re: Replacing 32-bit loop variable with 64-bit introduces performance deviations

#2
TLDR: Headline (and indeed bulk of article) is phantom symptom. True cause is register allocator behavior.

Specifically, allocator's handling of an instruction with a false dependency on register that's written to, coupled with multiple compilers being unaware of the false dependency.

Re: Replacing 32-bit loop variable with 64-bit introduces performance deviations

#3
This is why micro-benchmarking is Russian roulette.

When you distill a loop until you're finding the exact bottleneck in the system (pipelining, branch prediction, etc) you need to be very very careful you're measuring what you think you are. Otherwise you'll end up in this situation where you're benchmarking a compiler...

Re: Replacing 32-bit loop variable with 64-bit introduces performance deviations

#4
To elaborate on the justification for the answer:

    So Intel probably shoved popcnt into the same category to keep the processor design simple
In the processor design I work on, we do register dependency checks by partitioning all instructions into a set of "timing classes" and checking the dispatch delay needed between dependent register producers and consumers across all possible timing class pairs. The delays vary depending on available forwarding networks, resource conflicts, etc. Often times we groups instructions into sub optimal timing classes to simplify other parts of the design or just to make the dispatch logic simpler.

Intel's x86 core is waaaaay more complicated than the core I work on and has far more instructions, so I it's probably safe to say that they make these suboptimal classifications often. I strongly suspect that the false dependency was intentional and not a "hardware bug" as some of the StackOverflow comments seem to suggest.

Re: Replacing 32-bit loop variable with 64-bit introduces performance deviations

#5
post #2

TLDR: Headline (and indeed bulk of article) is phantom symptom. True cause is register allocator behavior. Specifically, allocator's handling of an instruction with a false dependency on register that's written to, coupled with multiple compilers being unaware of the false dependency.

Maybe one should add, that (as much I understood) it is a problem of the processor handling one specific (and rare) instruction. It does assume register dependencies that do not exist. It was shown, that AMD does not have this behavior. And it shows, that today's processors are enormous complex beasts.

The problem with the compilers was, that they where not aware of this behavior and thus generated sub-optimal code for this situation ... but compiler builders are also mere humans.

Re: Replacing 32-bit loop variable with 64-bit introduces performance deviations

#6
It should be noted that using 64-bit operands, even in 64-bit mode, incurs an extra penalty of 1 byte per instruction, for the REX prefix. The same applies to using the extended registers (the uncreatively-named "r8" through "r15".) This is very much not noticeable for microbenchmarks, where all the code of a loop fits in the cache, but for bigger ones, the effects of icache misses can become quite significant. A smaller instruction sequence that is slower than a larger one when microbenchmarked can become much faster once that code is benchmarked as part of a whole system.

Re: Replacing 32-bit loop variable with 64-bit introduces performance deviations

#7

It should be noted that using 64-bit operands, even in 64-bit mode, incurs an extra penalty of 1 byte per instruction, for the REX prefix. The same applies to using the extended registers (the uncreatively-named "r8" through "r15".) This is very much not noticeable for microbenchmarks, where all the code of a loop fits in the cache, but for bigger ones, the effects of icache misses can become quite significant. A sma…

(the uncreatively-named "r8" through "r15".)

I'd much rather have numbered registers that can be used for anything than named registers that have usage limitations.

Re: Replacing 32-bit loop variable with 64-bit introduces performance deviations

#8
post #7

It should be noted that using 64-bit operands, even in 64-bit mode, incurs an extra penalty of 1 byte per instruction, for the REX prefix. The same applies to using the extended registers (the uncreatively-named "r8" through "r15".) This is very much not noticeable for microbenchmarks, where all the code of a loop fits in the cache, but for bigger ones, the effects of icache misses can become quite significant. A sma…

(the uncreatively-named "r8" through "r15".) I'd much rather have numbered registers that can be used for anything than named registers that have usage limitations.

I suspect that aside was written tongue-in-cheek.

Re: Replacing 32-bit loop variable with 64-bit introduces performance deviations

#9
post #2

TLDR: Headline (and indeed bulk of article) is phantom symptom. True cause is register allocator behavior. Specifically, allocator's handling of an instruction with a false dependency on register that's written to, coupled with multiple compilers being unaware of the false dependency.

Maybe one should add, that (as much I understood) it is a problem of the processor handling one specific (and rare) instruction. It does assume register dependencies that do not exist. It was shown, that AMD does not have this behavior. And it shows, that today's processors are enormous complex beasts. The problem with the compilers was, that they where not aware of this behavior and thus generated sub-optimal code f…

Did they file a bug for gcc and clang?

Re: Replacing 32-bit loop variable with 64-bit introduces performance deviations

#10
post #4

To elaborate on the justification for the answer: So Intel probably shoved popcnt into the same category to keep the processor design simple In the processor design I work on, we do register dependency checks by partitioning all instructions into a set of "timing classes" and checking the dispatch delay needed between dependent register producers and consumers across all possible timing class pairs. The delays vary d…

I wouldn't classify it as intentional nor a "bug"; probably it's more of an oversight, as it's mentioned in the article that AMD's CPUs don't have this issue. Intel should definitely be made aware of this.

We can only speculate, but it's likely that Intel has the same handling for a lot two-operand instructions. Common instructions like add, sub take two operands both of which are inputs. So Intel probably shoved popcnt into the same category to keep the processor design simple.

On the other hand, MOV doesn't read both operands either.

Post reply on HN